平平无奇的前端总结:常见函数方法

159 阅读2分钟

近日,看八股文,学源码,一些汇总,记录于此,如有疑问,欢迎指正。

2.webp

防抖

function debounce(cb, delay, immediate){
    let timer;
    return function(){
        if(!timer&&immediate){
            cb.apply(this, arguments)
        }
        if(timer) clearTimeout(timer)
        timer = setTimeout(() => {
            cb.apply(this, arguments)
        }, delay)
    }
}

节流

function throttle(cb, delay, immediate){
    let timer, callNow = immediate;
    return function(){
        if(callNow){
            callNow = false;
            cb.apply(this, arguments)
        }
        if(!timer){
            timer = setTimeout(() => {
                cb.apply(this, arguments);
                timer = null;
            }, delay)
        }
    }
}

数组转树形结构

function arrayToTree(arr){
    let result = [], map = {};
    for(let item of arr){
        let pid = item.pid, id =item.id;
        if(!map[id]){
            map[id] = {
                children: []
            }
        }
        map[id] = {
            ...item,
            children: map[id].children
        }
        let mapItem = map[id];
        if(pid === 0){
            result.push(mapItem)
        }else{
            if(!map[pid]){
                map[pid] = {
                    children: []
                }
            }
            map[pid].children.push(mapItem)
        }
    }
    return result
}

数组中默认pid=0的项为树结构的顶层

arr = [
    { pid: 0, id: 1, name: '1' },
    { pid: 1, id: 2, name: '2' },
    { pid: 1, id: 3, name: '3' },
    { pid: 2, id: 4, name: '4' },
    { pid: 3, id: 5, name: '5' },
    { pid: 3, id: 6, name: '6' },
    { pid: 4, id: 7, name: '7' }
]
arrayToTree(arr)
[
    {
        "pid": 0,
        "id": 1,
        "name": "1",
        "children": [
            {
                "pid": 1,
                "id": 2,
                "name": "2",
                "children": [
                    {
                        "pid": 2,
                        "id": 4,
                        "name": "4",
                        "children": [
                            {
                                "pid": 4,
                                "id": 7,
                                "name": "7",
                                "children": []
                            }
                        ]
                    }
                ]
            },
            {
                "pid": 1,
                "id": 3,
                "name": "3",
                "children": [
                    {
                        "pid": 3,
                        "id": 5,
                        "name": "5",
                        "children": []
                    },
                    {
                        "pid": 3,
                        "id": 6,
                        "name": "6",
                        "children": []
                    }
                ]
            }
        ]
    }
]

类型检测

function typeOf(value){
    return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()
}

数据拷贝

function deepClone(target, map = new Map()){
    if(map.get(target)){
        return target
    }
    let constructor = target.constructor;
    if(/^(RegExp|Date)$/.test(constructor.name)){
        return new constructor(target)
    }
    if(target!==null && (typeof target === 'object' || typeof target === 'function')){
        map.set(target, true)
        if(typeof target === 'function'){
            return new Function('return '+target.toString())()
        }else{
            let result = Array.isArray(target)?[]:{};
            for(let key in target){
                if(target.hasOwnProperty(key)){
                    result[key] = deepClone(target[key], map)
                }
            }
            return result
        }
    }
    return target
}

数据拷贝(Symbol)

const isObject = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function')
const isFunction = obj => typeof obj === 'function'
function deepClone(target, map = new WeakMap()){
    if(map.has(target)){
        return map.get(target)
    }
    if(!isObject(obj)) return obj
    const constructor = obj.constructor;
    if(/^(Date|RegExp)$/.test(constructor.name)){
        return new constructor(obj)
    }
    let result = new constructor();
    if(isFunction(obj)){
        result = new Function('return '+obj.toString())
    }
    map.set(obj, result)
    [...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)].forEach(key => {
        result[key] = deepClone(obj[key], map)
    })
    return result
}

柯里化

function curry(fn){
    return function curried(...args){
        if(args.length < fn.length){
            return function(...args2){
                return curried.apply(this, args.concat(args2))
            }
        }
        return fn.apply(this, args)
    }
}
// 具体使用方式
function sum(a, b, c){
    return a + b + c
}
curry(sum)(1)(2)(3) // 6

sleep

async function sleep(delay){
    return new Promise((resolve, reject) => {
        setTimeout(resolve, delay)
    })
}
(async function(){
    console.log(Date.now())
    await sleep(1000)
    console.log(Date.now())
})()

继承

const inherit = (function(){
    let F = function () { }
    return function (target, origin) {
        F.prototype = origin.prototype;
        target.prototype = new F();
        target.prototype.constructor = target;
        target.prototype.originPrototype = origin.prototype
    }
})()

new操作符

function _new(constructor, ...args){
    if(typeof constructor !== 'function'){
        throw new Error('constructor must be a funciton')
    }
    let obj, result;
    obj = Object.create(constructor.prototype);
    result = constructor.apply(obj, args);

    if(result!==null && (typeof result === 'object' || typeof result === 'function')){
        return result;
    }
    return obj
}

Object.assign

  • 浅拷贝
  • 同名属性替换,数组视为对象存在索引覆盖
  • 取值函数,不会复制取值函数,只会使用最终属性值
  • 不能拷贝不可枚举属性,只拷贝自身属性
  • 可以拷贝symbol
  • target始终是一个对象,如果是基本类型,会被转成对应的基本包装类型,null和undefined无法转成对象,会报错
  • source参数如果是数字和布尔值,不会产生效果,字符串内部有iterator接口
  • target如果是字符串,转成基本包装类型时属性时只读的(writable属性为false)。此会导致Object.assign('a', 'bc')报错,TypeError: Cannot assign to read only property '0' of object '[object String]'
let str = Object('abc')
Object.getOwnPropertyDescriptors(a)
// ===>
{
    "0": {
        "value": "a",
        "writable": false,
        "enumerable": true,
        "configurable": false
    },
    "1": {
        "value": "b",
        "writable": false,
        "enumerable": true,
        "configurable": false
    },
    "2": {
        "value": "c",
        "writable": false,
        "enumerable": true,
        "configurable": false
    },
    "length": {
        "value": 3,
        "writable": false,
        "enumerable": false,
        "configurable": false
    }
}
function assign(target, ...source){
    if(target == null){
        throw new TypeError('Cannot convert undefined or null to object')
    }
    return source.reduce((prev, next) => {
        if(!(prev !==null &&(typeof prev === 'object' || typeof next === 'function'))){
            prev = new Object(prev)
        }
        if(next == null) return prev;
        [...Object.keys(next), ...Object.getOwnPropertySymbols(next)].forEach(key => {
            prev[key] = next[key]
        })
        return prev
    }, target)
}

instanceof

function instanceOf(left, right){
    let proto = Object.getPrototypeOf(left);
    while(true){
        if(proto == null) return false;
        if(proro === right.prototype) return true;
        proto = Object.getPrototypeOf(proto)
    }
}

首篇文章,以上。

1.webp