javascript常用方法实现【持续更新】

321 阅读3分钟

本篇文章旨在总结javascript的常用方法的实现,不定期积累更新,各路大神如有更加完美的实现,还望不吝赐教

1.事件代理

function delegateEvent(parentEle, childEle, type, fn){
    if(parentEle.addEventListener){
        parentEle.addEventListener(type, eventHandle, false);
    }else if(parentEle.attachEvent){
        parentEle.attachEvent('on' + type, eventHandle);
    }else{
        parentEle['on' + type] = eventHandle;
    }

    function eventHandle(e){
        e = e || window.event;
        const { target } = e;
        if(matchEle(target, childEle) && fn){
            fn.call(target, e);
        }
    }
    
    function matchEle(target, childEle){
        if(childEle.startWith('#')){
            return target.id ==== childEle.slice(1);
        }
        if(childEle.startWith('.')){
            return target.className && ~target.className.indexOf(childEle.slice(1))
        }

        return target.tagName.toLowerCase() === parentEle.toLowerCase();
    }
}

2.防抖函数

任务超过一定的时间间隔才会触发,一般用于输入框实时检索

function debounce(delay = 500, fn){
    let timer = Date.now();
    return function(){
        if(timer) clearTimeout(timer);
        timer = setTimeout((args)=>{
            fn.apply(this, args)
        }, delay, [...arguments])
    }
}

3.节流函数

任务在固定的时间内只能执行一次,一般用于scroll滚动,动画之类

function throttle(fn, delay = 500){
    let canRun = true
    return function(){
        if(canRun){
            canRun = false;
           setTimeout((args)=>{
               fn.apply(this, args);
               canRun = true;
           }, delay, [...arguments])
        }
    }
}

function throttle(fn, delay = 500){
    let timer = Date.now()
    return function(){
        let current = Date.now();
        if(current - timer > delay){
            fn.apply(this, [...arguments]);
            timer = current;
        }
    }
}

4. 对象数组深拷贝

function deepCopy(obj){
    const result = Array.isArray(obj) ? [] : {};
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            if(typeof obj[key] === 'object' && obj[key] !== null ){
                result[key] = deepCopy(obj[key]);
            }else{
                result[key] = obj[key];
            }
        }
    }
    return result;
}

5.数组洗牌算法

function arrayShuffle(arr){
    if(!Array.isArray(arr)){
        throw new Error('arguments[1] must is array');
    }
    let m = arr.length;
    while(m > 1){
        const index = Math.floor(Math.random() * m--);
        [arr[index], arr[m]] = [arr[m], arr[index]];
    }
    return arr;
}
// 概率抽奖
const proList = [
    {prizeId: 1, probability:20},
    {prizeId: 2, probability:50},
    {prizeId: 3, probability:30}
]
function generalLotteryList(proList){
    const arr = new Array(100);
    let i = 0;
    proList.forEach(item=>{
        arr.fill(item.prizeId, i, i + item.probability);
        i += item.probability;
    })
    return arrayShuffle(arr);
}
generalLotteryList(proList)

6.多维数组展开

function arrayFlat(arr) {
    if (!Array.isArray(arr)) throw new Error('arguments[0] must is array');
    let result = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        result = result.concat(Array.isArray(arr[i]) ? arrayFlat(arr[i]) : arr[i])
    }
    return result;
}
function arrayFlat(arr){
    return [].concat(...arr.map(e => {
        return Array.isArray(e) ? arrayFlat(e) : e;
    }))
}
function arrayFlat(arr) {
    if (!Array.isArray(arr)) throw new Error('arguments[0] must is array');
    return arr.reduce((result, val) => {
        return result.concat(Array.isArray(val) ? arrayFlat(val) : val)
    }, [])
}
function arrayFlat(arr, deep) {
    if (!Array.isArray(arr)) throw new Error('arguments[0] must is array');
    let result = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i]) && deep > 0) {
            result = result.concat(arrayFlat(arr[i], deep - 1));
        } else {
            result.push(arr[i])
        }
    }
    return result;
}

7.对象的深合并

注意区分与Object.assign区别,Object.assign不适合合并多层嵌套对象

function deepAssign(){
    const result = {};
    function assignValue(key, val){
        if(typeof result[key] === 'object' && typeof val === 'object'){
            result[key] = deepAssign(result[key], val);
        }else{
            result[key] = val;
        }
    }
    for(let i=0;i<arguments.length; i++){
        if(typeof arguments[i] !== 'object' || typeof arguments[i] === null) return;
        for(let key in arguments[i]){
            assignValue(key, arguments[i][key]);
        }
    }
    return result;
}

8. 函数柯里化

function carry(fn, n) {
    const result = (...allArgs) => allArgs.length === n ?
        fn(...allArgs) : (...args) => result(...[...allArgs, ...args])
    return result;
}

function f(a, b, c, d) {
    console.log(a, b, c, d)
}
const r = carry(f, 4);
r(1, 2)(4, 3)
r(1, 2, 3)(4)

9.获取dom元素位置

function getTagPos(ele, result = [], resultStr = []){
    if(!ele) return {
        result:result.join('>'),
        resultStr: resultStr.join('>')
    };
    let deep = 0, deepStr = [ele.tagName], current = ele.previousElementSibling;
    while(current){
        deep++;
        deepStr.unshift(current.tagName);
        current = current.previousElementSibling;
    }
    result.unshift(`${ele.tagName}:${deep}`);
    resultStr.unshift(deepStr.join('|'));
    return getTagPos(ele.parentElement, result, resultStr);
}
{
    "result": "HTML:0>BODY:1>DIV:0>DIV:0>DIV:3>DIV:0",
    "resultStr": "HTML>HEAD|BODY>DIV>DIV>DIV|DIV|DIV|DIV>DIV"
}

10. compose实现

实现一

function compose(...arrFn){
    const len = arrFn.length;
    if(len === 0) return args => args;
    if(len === 1) return len[0];
    return arrFn.reduce((a, b) => {
        return (...args)=> a(b(...args))
    })
}
function compose(...arrFn){
    return (...args)=>{
        return arrFn.reverse().reduce((a, b, c)=>{
            return c === 0 ? b.apply(null, args) : b.call(null, a);
        }, null)
    }
}

实现二

function f1(num){
    return num + 10;
}
function f2(num){
    return num + 20;
}
function f3(num){
    return num + 30;
}
function f4(num){
    return num + 40;
}

console.log(compose(f4, f3, f2, f1)(4)) //104