JS常见手写


浅比较

/**
 * 浅比较(如果是对象,只比较第一层属性,与深比较/深拷贝相比性能更好,平常够用)
 * @param obj1 任意基本类型或引用类型
 * @param obj2 任意基本类型或引用类型
 * @returns 是否同一对象
 */
function shallowEqual(obj1: any, obj2: any): boolean {
    // 同基本类型,或同引用地址,返回true
    if (obj1 === obj2) return true;

    // 非对象类型 或 为null 返回 false
    if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 == null) return false

    const keys1 = Object.keys(obj1)
    const keys2 = Object.keys(obj2)
    if (keys1.length !== keys2.length) return false

    // 如果obj2中没有obj1中的某个属性,或该属性值不相等返回false
    for (let key of keys1) {
        if (!obj2.hasOwnProperty(key) || obj1[key] !== obj2[key]) {
            return false
        }
    }

    return true
}

const obj11 = { a: 1 }
const obj12 = { a: 1 }
console.log(shallowEqual(obj11, obj12)); // true

手写深拷贝

__浅拷贝__,如果复制的对象是基本数据类型,拷贝的就是值,如果是引用类型,拷贝的就是内存地址,一个对象改变会影响另一个对象

JSON.parse(JSON.stringify()) 基本能用版

  1. JSON.parse(JSON.stringify()),写法简单,但无法拷贝函数,循环引用,或特殊引用类型.

forIn遍历,递归自身,丐版

function clone(target) {
    if (typeof target !== 'object') return target;

    let cloneTarget = {};
    for (const key in target) {
        cloneTarget[key] = clone(target[key]);
    }
    return cloneTarget
};

cloneTarget=[]兼容数组,map解决循环引用,够用了版

/**
 * 深拷贝
 * @param {Object} target 要拷贝的对象
 * @param {WeakMap} map 用于存储循环引用对象的地址
 */
function deepClone(target, map = new WeakMap()) {
    if (typeof target !== 'object') return target

    if (map.get(target)) {
        return map.get(target)
    }

    const cloneTarget = Array.isArray(target) ? [] : {}
    map.set(target, cloneTarget)

    for (const key in target) {
        if (Object.hasOwnProperty.call(target, key)) {
            cloneTarget[key] = deepClone(target[key], map);
        }
    }
    return cloneTarget
}

WeakMap弱引用 与 {}强引用

forIn循环效率低,while循环效率高,性能优化版

函数类型及特殊引用类型得专门判断

MapSet 等类型得专门判断

手写防抖节流

防抖和节流都是防止某一事件频繁触发

防抖(debounce)

施法前摇,在读条期间再次触发会打断施法,重新读条,直到正常读条结束,触发函数。

function debounce(fn, wait) {
    let timer;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, arguments);
        }, wait);
    };
}

场景: 浏览器窗口resize,文本编辑器自动保存,输入框智能提示
防抖重在清零 clearTimeout(timer)

节流

节流重在加锁 timer=timeout,控制事件发生频率,限流,单位时间内只发生一次
防抖是在等用户给出最终答案 再触发,节流就是防止频繁触发 限流 锁。

function throttle(fn, wait) {
    let timer;
    return function () {
        if (timer) return
        timer = setTimeout(() => {
            fn.apply(this, arguments);
            timer = null;
        }, wait);
    };
}

如果防抖在首次触发怎么写?

实现一个节流函数? 如果想要最后一次必须执行的话怎么实现?

加上对上下文的处理

手写排序

冒泡排序 插入排序 选择排序

快速排序 归并排序

类的继承

手写扁平数组转tree


文章作者: 罗紫宇
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗紫宇 !
 上一篇
Flex布局 Flex布局
2009年,W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
2023-03-06
下一篇 
罗紫宇-前端开发-四年 罗紫宇-前端开发-四年
【绩效优异】两年间,共获1次年度A1(前10%),2次季度A1,4座季度标兵奖杯,正式入职以来绩效未尝低于A2(A3/B1为优秀)。
2023-03-02
  目录