前端常用算法

1. 通過parentId生成樹形結(jié)構(gòu)

let data = [
        {
            id: '1-2-1',
            lable: '第1-2-1級(jí)',
            parentId: '1-2'
        },
        {
            id: '1',
            lable: '第1級(jí)'
        },
        {
            id: '1-1',
            lable: '第1-1級(jí)',
            parentId: '1'
        },
        {
            id: '2-1',
            lable: '第2-1級(jí)',
            parentId: '2'
        },
        {
            id: '4',
            lable: '第4級(jí)'
        },
        {
            id: '2-2',
            lable: '第2-2級(jí)',
            parentId: '2'
        },
        {
            id: '1-2',
            lable: '第1-2級(jí)',
            parentId: '1'
        },
        {
            id: '2',
            lable: '第2級(jí)'
        },
        {
            id: '3',
            lable: '第3級(jí)'
        },
        {
            id: '2-2-1',
            lable: '第2-2-1級(jí)',
            parentId: '2-2'
        },
    ]
  • 第一種
    function generateTree(data) {
        const tree = [];
        const parentMap = {};
        data.forEach(item => {
            parentMap[item.id] = true;
        });
        data.forEach(item => {
            if (!item.parentId) {
                // 在原始數(shù)據(jù)中不存在parentId時(shí)就是根節(jié)點(diǎn),tree中首先放入這類節(jié)點(diǎn)
                item._root = true;
                tree.push(item);
            } else if (!parentMap[item.parentId]) {
                // 一個(gè)節(jié)點(diǎn)有parentId,但這個(gè)parentId對(duì)應(yīng)id節(jié)點(diǎn)沒有也作為一個(gè)根節(jié)點(diǎn)
                tree.push(item);
            }
            data.forEach(each => {
                // 對(duì)每一個(gè)節(jié)點(diǎn)遍歷所有節(jié)點(diǎn),找到該節(jié)點(diǎn)的子節(jié)點(diǎn)
                // 在遍歷所有節(jié)點(diǎn)過程中,如果遍歷到該節(jié)點(diǎn)本身直接跳過
                // 如果遍歷到的節(jié)點(diǎn)的parentId與該節(jié)點(diǎn)的id相同,此節(jié)點(diǎn)就是該節(jié)點(diǎn)的子節(jié)點(diǎn)
                if (each.id === item.id) return;
                if (each.parentId === item.id) {
                    if (!item.children) return (item.children = [each]);
                    item.children.push(each);
                }
            });
        });
        return tree
    }
  • 第二種(時(shí)間復(fù)雜度最?。?/li>
    function createTree(data){
        const treeList = [];
        const treeMap = {};
        // 如果原始數(shù)組長(zhǎng)度為0或數(shù)組不存在,返回樹結(jié)構(gòu)為[]
        if (!data || data.length === 0) {
            return treeList;
        }
        // 將原始數(shù)據(jù)的每個(gè)節(jié)點(diǎn)存入一個(gè)對(duì)象中,這個(gè)對(duì)象的key為節(jié)點(diǎn)id,value為節(jié)點(diǎn)自身
        for (let i = 0; i < data.length; i++) {
            treeMap[data[i].id] = { ...data[i], children: [] };
        }
        // 遍歷上一步生成的節(jié)點(diǎn)對(duì)象,如果對(duì)象一個(gè)value的parentId存在,將該節(jié)點(diǎn)作為key為parentId的節(jié)點(diǎn)的children值
        // 如果對(duì)象一個(gè)value的parentId不存在則為根節(jié)點(diǎn)存入樹結(jié)構(gòu)數(shù)組中
        for (let key in treeMap) {
            const value = treeMap[key];
            if (value.parentId !== null && value.parentId !== '' && value.parentId !== undefined) {
                if (!treeMap[value.parentId]) continue;
                treeMap[value.parentId].children.push(value);
            } else {
                treeList.push(value);
            }
        }
        return treeList
    }

2. 實(shí)現(xiàn)數(shù)組的隨機(jī)排序

var arr = [1,2,3,4,5,6];
function randomOrder(i,j){
  return Math.random() > 0.5 ? -1 : i
}
arr.sort(randomOrder)

3. 兼容性較強(qiáng)的事件偵聽器函數(shù)

        const EventUtils = {
            // 視能力分別使用dom0||dom2||IE方式 來綁定事件
            // 添加事件
            addEvent: function(element, type, handler) {
                if (element.addEventListener) {
                    element.addEventListener(type, handler, false);
                } else if (element.attachEvent) {
                    element.attachEvent("on" + type, handler);
                } else {
                    element["on" + type] = handler;
                }
            },
            // 移除事件
            removeEvent: function(element, type, handler) {
                if (element.removeEventListener) {
                    element.removeEventListener(type, handler, false);
                } else if (element.detachEvent) {
                    element.detachEvent("on" + type, handler);
                } else {
                    element["on" + type] = null;
                }
            },
            // 獲取事件目標(biāo)
            getTarget: function(event) {
                return event.target || event.srcElement;
            },
            // 獲取 event 對(duì)象的引用,取到事件的所有信息,確保隨時(shí)能使用 event
            getEvent: function(event) {
                return event || window.event;
            },
            // 阻止事件(主要是事件冒泡,因?yàn)?IE 不支持事件捕獲)
            stopPropagation: function(event) {
                if (event.stopPropagation) {
                    event.stopPropagation();
                } else {
                    event.cancelBubble = true;
                }
            },
            // 取消事件的默認(rèn)行為
            preventDefault: function(event) {
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            }
        };

4. 實(shí)現(xiàn) flatten 函數(shù)

var arr = [1, 2, 3, [4, 5], [6, [7, [8]]]]
  • 第一種方法:使用數(shù)組的reduce方法
function flatten(arr) {
  return arr.reduce((result,item)=>{
    return result.concat(Array.isArray(item) ? flatten(item) : item)
  },[])
}

reduce包含兩個(gè)參數(shù):回調(diào)函數(shù),傳給total的初始值
求數(shù)組的各項(xiàng)值相加的和:

arr.reduce((total, item)=> {  // total為之前的計(jì)算結(jié)果,item為數(shù)組的各項(xiàng)值
    return total + item;
}, 0);
  • 第二種方法:將數(shù)組轉(zhuǎn)換為字符串,然后轉(zhuǎn)換為一維數(shù)組
function flatten(arr) {
  return arr.toString().split(",").map((item)=>{
    return +item
  })
}

或者(arr.join(",")能將數(shù)組多維或一維arr轉(zhuǎn)換為以,分隔的字符串)

function flatten(arr) {
  return arr.join(',').split(",").map((item)=>{
    return +item
  })
}
  • 第三種方法:遞歸
function flatten(arr) {
  var res = [];
  for(let item of arr){
    if(Array.isArray(item)){
      res = res.concat(flatten(item))
    }else{
      res.push(item)
    }
  }
  return res
}
  • 第四種方法:擴(kuò)展運(yùn)算符
    es6的擴(kuò)展運(yùn)算符能將二維數(shù)組變?yōu)橐痪S
[].concat(...[1, 2, 3, [4, 5]]);  // [1, 2, 3, 4, 5]
function flatten(arr) {
  while(arr.some(item=>Array.isArray(item))){
    arr = [].concat(...arr)
  }
  return arr
}

5. 實(shí)現(xiàn)一個(gè)sleep

sleep函數(shù)作用是讓線程休眠,指定時(shí)間一到便重新喚起。

function sleep(delay){
  var start = (new Date()).getTime()
  while((new Date()).getTime() - start < delay){
    continue;
  }
}

function test(){
  console.log("11111");
  sleep(2000);
  console.log("22222");
}

test()   // 先打印出11111,2秒之后打印22222

6. 解析 URL 的查詢參數(shù)為對(duì)象

let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* 結(jié)果
{ user: 'anonymous',
  id: [ 123, 456 ], // 重復(fù)出現(xiàn)的 key 要組裝成數(shù)組,能被轉(zhuǎn)成數(shù)字的就轉(zhuǎn)成數(shù)字類型
  city: '北京', // 中文需解碼
  enabled: true, // 未指定值得 key 約定為 true
}
*/
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
let uel2 = window.location.search;      // 獲取url查詢字符串參數(shù)

function parseParam(url){
    let message = /.+\?(.+)/.exec(url)[1]; //   獲取查詢字符串
  let messArr = message.split('&'); // 獲得將字符串以&分割得到的數(shù)組
  let messObj = {}; //  結(jié)果對(duì)象
  for(let item of messArr){
    if(/=/.test(item)){  // 處理有value的參數(shù)
      let [key,value] = item.split('=');
      value = decodeURI(value); //  解碼
      value = decodeURIComponent(value);    //  解碼
      value = /^\d+$/.test(value) ? parseFloat(value) : value;  
      //    參數(shù)值全為數(shù)字時(shí)就變?yōu)閿?shù)字
      if(messObj.hasOwnProperty(key)){  //  一個(gè)參數(shù)多次出現(xiàn)時(shí),參數(shù)的值變?yōu)閿?shù)組
        messObj[key] = [].concat(messObj[key],value)
      } else {
        messObj[key] = value;
      }
    }else{  //  沒有value的參數(shù)設(shè)為true
      messObj[item] = true;
    }
  }
  return messObj;
}

7. 模板引擎實(shí)現(xiàn)

var template1 = '我是{{name}},年齡{{age}},性別{{sex}}';
var data1 = {
  name: '小明',
  age: 18
}
render(template1, data1); // 我是小明,年齡18,性別undefined

function render(template,data){
  var reg = /\{\{(\w+)\}\}/g;
  const orgTem = template;
  while(true) {
    var match = reg.exec(orgTem);
//     正則的exec函數(shù)在每次匹配時(shí)是從上一次匹配的結(jié)束位置開始,
//     因此,為了保證匹配的位置不變,循環(huán)時(shí)需要保證其中的值保持不變
    if (!match) break;
    template = template.replace(match[0], data[match[1]])
  }
  return template
}

8. 轉(zhuǎn)化為駝峰命名

var name = "get-element-by-id"

function changeName(name){
  var newName = name.replace(/(\-\w)/g, function(match){
    return match[1].toUpperCase()
  })
  return newName
}

changeName(name)

9. 查找字符串中出現(xiàn)最多的字符和個(gè)數(shù)

var str1 = "abcabcabcbbccccc";

function findMostL(str){
    let obj = {};
  for(let i = 0; i < str.length; i++){
    if(obj[str[i]]){
      obj[str[i]] += 1
    }else{
      obj[str[i]] = 1;
    }
  }
  let max = 0;
  let moreLetter = [];
  for(let key in obj){
    max = Math.max(obj[key],max)
  }
  for(let key in obj){
    if(obj[key] === max){
      moreLetter.push(key);
    }
  }
  console.log('出現(xiàn)次數(shù)最多的字母是:',moreLetter,'出現(xiàn)次數(shù)為',max);
}
findMostL(str1)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 1.排序 以下兩個(gè)函數(shù)是排序中會(huì)用到的通用函數(shù),就不一一寫了 2.時(shí)間復(fù)雜度 通常使用最差的時(shí)間復(fù)雜度來衡量...
    程序員阿野閱讀 382評(píng)論 0 2
  • 沒錯(cuò),作為一個(gè)菜鳥,我真的不認(rèn)為前端需要用到算法。我不是朝后段喊一聲,什么都有了么???(黑人問號(hào))然而實(shí)際上,前...
    kathyb24閱讀 2,215評(píng)論 0 2
  • /*去重*/ function delRepeat(arr){ var newArray=new Array();...
    Hedgehog_Dove閱讀 2,001評(píng)論 0 2
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 129,734評(píng)論 2 7
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者,不喜歡去冒險(xiǎn),但是人生放棄了冒險(xiǎn),也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 7,928評(píng)論 0 4

友情鏈接更多精彩內(nèi)容