记录自学前端中的小问题

53 阅读2分钟

1.手写防抖节流

function debounce(f, wait) {
    let timer
    return (...args) => {
        clearTimeout(timer)
        timer = setTimeout(() => {
            f(...args)
        }, wait)
    }
}
function throttle(f, wait) {
    let timer
    let _this = this
    return (...args) => {
        if (timer) return
        timer = setTimeout(() => {
            f.call(_this,...args)
            timer = null 
            //在n秒后执行完毕关闭定时器,在n秒内未执行函数
            //定时器一直存在,导致函数在n秒内只能执行一次
        }, wait)
    }
}

2.手写bind

if (!Function.prototype.bind) {
    Function.prototype.bind = function (o/*,args*/) {
        let self = this
        let boundArgs = arguments //将bind对应的参数保存
        return () => { //函数可以接受到参数
            let args = [] //储存需要bind的参数
            let i
            for (i = 1; i < boundArgs.length; i++) {
                args.push(boundArgs[i])
            }
            for (i = 0; i < arguments.length; i++) {
                args.push(arguments[i])
            }
            return self.apply(o, args)
        }
    }
}

bind函数多次调用会以第一次调用的this为准,而softbind会以最后一次为准

3.闭包案例

//闭包 --- 一个函数返回另一个函数
function bibao() {
    let a = 1
    return () => {
        return a
    }
}
//意义: 延长变量生命周期 ; 创造私有环境
//闭包: 变量会常驻内存 不会被垃圾回收

4.手写compose函数,从右向左结合函数

const compose = (...func) => {
    return func.reduce(
        //先转置,从右往左结合函数
        (f, g) =>
            (...args) =>
                f(g(...args)) 
    )
}

const sum = x => x + 5
const multi = x => x * 10
const add = x => x + 10
console.log(compose(sum, multi, add)(10))

5.实现loadsh.get 获取对应路径的值

//实现loadsh.get() _.get(object,path,defaultValue) 获取对应路径的值
//a[0][1][2] => a.0.1.2 => [a,0,1,2]
const get = (o, path = '', defaultValue) => {
    if (typeof path !== 'string' && !Array.isArray(path)) {
        throw new Error(`${path} is not string or array`)
    }
    if (!Array.isArray(path)) {
        //如果不是数组,只能是字符串
        const paths = path
            .replace(/\[(\w+)\]/g, '.$1')
            .replace(/\['(\w+)'\]/g, '$1')
            .replace(/\["(\w+)"\]/g, '$1')
            .split('.')
    }
    const paths = path
    let res = o
    for (const p of paths) {
        res = res?.[p];//存在则读取属性
    }
    return res == undefined ? defaultValue : res
}

const test = { a: { b: { c: 100 } } }
console.log(get(test, 'a.b.c', 100), get(test, 'a.c', 200), get(test, ['a', 'b', 'c'], 200));

6.在微任务之中添加微任务,该任务会优先于其他任务,所以递归调用微任务应谨慎处理

7.对象扁平化

function flatter(obj) {
    let ans = {}

    if (Object.prototype.toString.call(obj) !== '[object Object]') {
        return obj
    }

    function helper(key, value) {
        if (typeof value !== 'object') {
            if (key) ans[key] = value
        } else if (Array.isArray(value)) {
            if (value.length == 0) {
                ans[key] = []
            }
            for (let i in value) {
                //跟之前的key结合,形成新的key值
                helper(`${key}[${i}]`, value[i])
            }
        } else if (Object.prototype.toString.call(obj) == '[object Object]') {
            let keys = Object.keys(value)
            if (keys.length == 0 && key) {
                ans[key] = {}
            }
            keys.forEach(item => {
                helper(key ? `${key}.${item}` : `${item}`, value[item])
            })
        }
    }
    helper('', obj)

    return ans
}

8.实现promise.all

//实现promise.all
const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p2 延时一秒')
    }, 1000)
})
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p3 延时两秒')
    }, 2000)
})

function promiseAll(promiseArr) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promiseArr)) throw new Error('syntax error') //错误处理

        let ans = []
        let count = 0
        for (let i = 0; i < promiseArr.length; i++) {
            Promise.resolve(promiseArr[i]).then(res => {
                count++
                ans[i] = res
                if (count == promiseArr.length) {
                    resolve(ans)
                }
            }).catch(err => {
                reject(err)
            })
        }
    })
}

9.实现promise.race 中一个就返回

function promiseRace(promiseArr) {
    if (!Array.isArray(promiseArr)) throw new TypeError('syntax error')
    if (promiseArr.length === 0) return
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
            Promise.resolve(promiseArr[i])
                .then(res => {
                    resolve(res)
                })
                .catch(err => {
                    reject(err)
                })
        }
    })
}

10.Promise.any 所有失败返回失败,一个成功返回成功 ,忽略所有拒绝值,直到第一个成功

function promiseAny(promiseArr) {
    if (!Array.isArray(promiseArr) || promiseArr.length == 0) {
        return Promise.reject('TypeError')
    }

    return new Promise((resolve, reject) => {
        let count = 0, ans = []
        for (let i = 0; i < promiseArr.length; i++) {
            Promise.resolve(promiseArr[i])
                .then(value => {
                    resolve(value)
                })
                .catch(err => {
                    count++
                    ans[i] = err
                    if (count == promiseArr.length) {
                        reject(ans)
                    }
                })
        }
    })
}

11.ES5实现类以及继承

function Animal(age){
    this.age = age
    this.eat = function(){

    }
}

function Cat(){
    Animal.call(this)
}

Cat.prototype = Object.create(Animal.prototype)
Cat.prototype.constructor = Cat