面试/工作常见算法(持续更新)

本文详细介绍了JavaScript中的冒泡排序算法,以及call、apply和bind的实现,这些都是JavaScript基础中重要的函数调用方式。此外,还探讨了如何进行对象的深拷贝,包括处理循环引用的情况。最后,文章讨论了防抖函数的实现,用于优化事件监听器中的频繁触发问题。这些内容对于深入理解JavaScript语言和提高编程技巧非常有帮助。
摘要由CSDN通过智能技术生成

1. 冒泡算法
注:重复从第一个位置开始,比较相邻的元素,前>后,则交换位置。最右已经最大的数不用再比较。

function bubble(arr) {
    if (!Array.isArray(arr)) {
        return
    }
    let len = arr.length
    for (let i = 0; i < len - 1; i++) {
        //随着数组末尾最大的数越来越多,遍历的次数应该越来越小
        for (let j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                //交换元素位置
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr
}

2.call、apply、bind实现
注:众所周知,call、apply是一样的,只是传参有点不一样,前者字符串,后者数组。 手写虽然没必要,但是面试笔试可能用到,且需要封装在所有函数的原型上。

call:

/**
 * 
 * @param {*} thisArg this绑定谁
 * @param  {...any} args 剩余参数
 * @returns 
 */
// 1.给所有函数添加mycall方法
Function.prototype.mycall = function (thisArg, ...args) {
    // 拿到调用这个方法的函数
    let fn = this
    //判断传入thisArg是否对象类型
    thisArg = (thisArg == 0 || thisArg) ? Object(thisArg) : window
    thisArg.fn = fn
    let result = thisArg.fn(...args)
    delete thisArg.fn
    //或者
    // fn.call(thisArg)
    //拿到结果返回出去
    return result
}
//测试代码
// function foo(num1, num2) {
//     console.log(num1 + num2, this);
//     return num1 + num2
// }

// const count = foo.wqcall('abc', 10, 20)
// console.log(count);

apply:

//自己实现apply
Function.prototype.myapply = function (thisArg, argArray = []) {
//可能fn函数有重复,用symbol就不会重复了
   let s1 = Symbol('fn')
    let fn = this
    thisArg = (thisArg === 0 || thisArg) ? Object(thisArg) : window
    thisArg[s1] = fn
    const result = thisArg[s1](...argArray)
    delete thisArg[s1]
    return result
}

bind:

/**
 * 
 * @param {*} thisArg this绑定谁
 * @param  {...any} argArray 剩余参数
 * @returns 
 */
Function.prototype.mybind = function (thisArg, ...argArray) {
    // 1.获取真实需要调用的函数
    var fn = this
    // 2.绑定this
    thisArg = (thisArg == 0 || thisArg) ? Object(thisArg) : window
    //bind要用函数代理 args是调用bind返回的函数时传的参
    function proxyFn(...args) {
        thisArg.fn = fn
        var finalArgs = [...argArray, ...args]
        var result = thisArg.fn(...finalArgs)
        delete thisArg.fn
        return result
    }
    return proxyFn
}


function foo(num1, num2, num3) {
    console.log("foo函数执行", this, num1, num2, num3);
}

var fn = foo.wqbind("bcb", 1, 2)
fn(3)

3. 深拷贝

//对obj进行深拷贝
let s1 = Symbol('aaa')
let s2 = Symbol('bbb')
const obj = {
    name: 'wq',
    friends: {
        name: 'wk',
        borthers: 'wdd'
    },
    hobbies: ['aaa', 'bbb', 'ccc'],
    foo: function () {
        console.log('函数');
    },
    [s1]: 'abc',
    s2: s2,
    set: new Set(['aaa', 'bbb', 'ccc']),
    map: new Map([['aaa', 'bbb'], ['ccc', 'ddd']])

}
//判断是否是对象的工具函数
function isObject(value) {
    const valueType = typeof value
    return (value !== 'null') && (valueType === 'object' || valueType === 'function')
}
//深拷贝
function deepClone(originValue, map = new WeakMap()) {
    //判断是否是set
    if (originValue instanceof Set) {
        return new Set([...originValue])
    }
    //判断是否是map
    if (originValue instanceof Map) {
        return new Map([...originValue])
    }
    //判断是否是symbol
    if (typeof originValue === 'symbol') {
        return Symbol(originValue.description)
    }
    //判断是否是函数
    if (typeof originValue === 'function') {
        return originValue
    }
    //如果不是对象,就直接返回值
    if (!isObject(originValue)) {
        return originValue
    }
    //如果map里包含这个对象,则是循环引用
    if (map.has(originValue)) {
        return map.get(originValue)
    }
    //如果是对象或者数组
    const newObject = Array.isArray(originValue) ? [] : {}
    map.set(originValue, newObject)
    for (const key in originValue) {
        newObject[key] = deepClone(originValue[key], map)
    }
    //symbol无法遍历出来,特殊处理
    const symbolKeys = Object.getOwnPropertySymbols(originValue)
    for (const skeys of symbolKeys) {
        newObject[skeys] = deepClone(originValue[skeys], map)
    }
    return newObject
}

加入循环引用测试

obj.info = obj
const newObject = deepClone(obj)
obj.friends.name = 'ssss'
console.log(newObject);

4.防抖

/**
 * @param {*} fn 调用的函数
 * @param {*} delay 延时多久
 * @param {*} immediate 是否立即调用
 * @returns 闭包
 */
function debounce(fn, delay, immediate = true) {
    let timer = null
    const _debounce = function (...args) {
        if (timer) clearTimeout(timer)
        if (immediate) {
            let now = !timer
            timer = setTimeout(() => {
                timer = null
            }, delay);
            now && fn.apply(this, args)
        } else {
            timer = setTimeout(() => {
                timer = null
                fn.apply(this, args)
            }, delay);
        }

    }
    return _debounce
}

//测试
 const inputEl = document.querySelector("input")
    let counter = 0
    const inputChange = function (event, a) {
        console.log(`发送了第${++counter}次网络请求`, this, event, a);

    }
    inputEl.oninput = debounce(inputChange, 2000, false)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值