前端面试手撕代码小集合(仍在补充中)

本文分享了面试过程中常被问到的Promise API实现、深拷贝函数及常见排序算法,包括Promise.all、Promise.race、Promise.finally等,并提供了实例代码。深入浅出地探讨了JavaScript Promise的用法和深拷贝的实现技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上岸半个月,开始回来学习写博客,先看了之前自己写的面经,决定先把一些常见的题目总结出来
(以下皆为面试bat字节时遇到的题目)
这里直接上代码,测试有问题的欢迎各位在评论区指出,注释看不懂其中代码也欢迎提出问题

实现promise的API

Promise.all

  • 参数:数组
  • 返回:一个promise对象
  • 功能:该方法接受一个数组作为参数,数组成员为Promise对象,若不是Promise对象,则先使用Promise.resolve方法变为对象。而事实上,数组参数中的每个值都会经过Promise.resolve方法的过滤。若数组中所有Promise对象的状态都变成已成功,则该方法返回的Promise对象的状态也变为已成功;若数组中有一个Promise对象状态变为已失败,则第一个变为已失败的对象的返回值传递给最后返回的Promise对象,该对象状态也变为已失败。
Promise._all = function(promises){
    return new Promise((resolve,reject)=>{
        // 将可遍历的类型转为数组形式
        promises = Array.from(promises)
        // 若数组长度为0,则直接resolve([])
        if(promises.length === 0){
            resolve([])
        }else{
            // 使用一个变量count来计算当前已完成的promise
            let count = 0
            for(let i=0;i<promises.length;i++){
                Promise.resolve(promises[i]).then(val=>{
                    promises[i] = val
                    // 若完成的promise数量和数组长度一致,说明全部完成,则返回处理好的数组
                    if(++count === promises.length){
                        resolve([promises])
                    }
                }).catch(err=>{
                    reject(err)
                })
            }
        }
    })
}

Promise.race

  • 参数:数组
  • 返回:一个promise对象
  • 功能:该方法与Promise.finally一样,都传入一个数组做为参数,但是返回的promise对象的状态,由数组中最先发生状态改变的promise决定,如果传入一个空数组,状态永远不会发生改变
Promise._race = function(promises){
    promises = Array.from(promises)
    return new Promise((resolve,reject)=>{
        promises.forEach(p=>{
            Promise.resolve(p).then(val=>{
                resolve(val)
            }).catch(err=>{
                reject(err)
            })
        })
    })
}

Promise.finally

  • 参数:一个回调方法
  • 返回:一个promise对象
    -功能:Promise.finally执行的时候,不管原来的状态变为resolve或是变为reject,都会去执行传入的回调方法
Promise._finally = function(callback){
    return this.then(val=>{
        return Promise.resolve(callback()).then(()=>{
            return val
        })
    },err=>{
        return Promise.resolve(callback()).then(()=>{
            throw err
        })
    })
}

深拷贝

const deepClone =(initalObj) =>
{
    if (typeof initalObj !== 'object') {//如果是基本类型直接返回值
        return initalObj
    }
    const obj = Array.isArray(initalObj)?[]:{};//可能是对象或者数组
    for (const key in initalObj) {
        if (typeof initalObj[key] === 'object') {//对于对象元素,deepclone
            //递归返回新的对象
            obj[key] = deepClone(initalObj[key]);
        } else if (typeof initalObj[key] === 'function') {//对于函数,用bind拷贝
            //返回新函数
            obj[key] = initalObj[key].bind(obj);
        } else {
            //基本类型直接返回
            obj[key] = initalObj[key];
        }
    }
    return obj;
}

实现一个bind

Function.prototype.bind2 = function(context,...rest){
    if(typeof this !== "function"){
        throw new TypeError("Uncaught TypeError: Bind must be called on a function") // 不是函数时抛出错误
    }
    var self = this // 保存这个方法
    var Fn = function () {} // 使用一个空函数做为继承的中间函数
    var fBound = function (...inRest){
        self.apply(this instanceof Fn ? this : context, rest.concat(inRest)) // 这里的处理是当使用new运算符时,this指向被改变,我们就不能使用context做为this了,new运算符优先级高于bind
    }
    
    // 本来可以通过fBound.prototype = self.prototype实现原型链绑定
    // 但是这也导致了当我们改变fBound.prototype时,因为和self也就是原函数使用了同一个引用,所以会修改原函数的prototype

    Fn.prototype = self.prototype
    fBound.prototype = new Fn()
    return fBound
}

实现一个new

function _new(c,...args){
    if(typeof c !=="function"){
        throw new TypeError(`${c} is not a constructor`) // 判断不是函数时抛出错误
    }
    let obj = Object.create(c.prototype) // 实现继承
    let res = c.call(obj,...args) // 绑定this
    return typeof res === "object"||typeof res === "function"?res:obj // 若返回的是对象,则返回该对象,否则返回实例
}

大数相加

var bigAdd = function(n1, n2) {
    n1 += ""
    n2 += ""
    let i1 = n1.length-1
    let i2 = n2.length-1
    let flag = 0
    let res = ""
    while (i1 >= 0 || i2 >= 0 || flag) {
        let num1 = Number(n1[i1--]) || 0
        let num2 = Number(n2[i2--]) || 0
        let sum = num1 + num2 + flag
        flag = 0
        if(sum >= 10){
            flag = 1
            sum -= 10
        }
        res = sum + res
    }
    return res
}

数组中出现的数字次数大于2/n的数

function find(arr){
    let value = arr[0],
        count = 1
    for(let i=1;i<arr.length;i++){
        if(count==0){
            count++
            value = arr[i]
        }else if(value === arr[i]){
            count++
        }else{
            count--
        }
    }
    return value
}

排序算法

冒泡

function bubbleSort(arr) {
    for (let i = 0; i < arr.length - 1; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                let temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
        }
    }
    return arr
}

插入

function insertSort(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = i; j > 0; j--) {
            if (arr[j] < arr[j - 1]) {
                let temp = arr[j]
                arr[j] = arr[j - 1]
                arr[j - 1] = temp
            }
        }
    }
    return arr
}

选择

function chooseSort(arr) {
    let maxIndex, maxNum, temp
    for (let i = 0; i < arr.length - 1; i++) {
        maxIndex = 0
        maxNum = arr[0]
        for (let j = 0; j < arr.length - i; j++) {
            if (arr[j] > maxNum) {
                maxIndex = j
                maxNum = arr[j]
            }
        }
        temp = arr[arr.length - i - 1]
        arr[maxIndex] = temp
        arr[arr.length - i - 1] = maxNum
    }
    return arr
}

快速

function fastSort(arr) {
    if (arr.length <= 1) {
        return arr
    } else {
        let sign = arr[0],
            low = 0,
            high = arr.length - 1
        while (low < high) {
            while (arr[low + 1] < sign && low < high) {
                arr[low] = arr[low + 1]
                low++
            }
            if (low !== high) {
                let temp = arr[low + 1]
                arr[low + 1] = arr[high]
                arr[high] = temp
                high--
            }
        }
        arr[low] = sign
        return [...fastSort(arr.slice(0, low)), sign, ...fastSort(arr.slice(low + 1))]
    }
}

归并

function merageSort(arr) {
    let len = arr.length
    if (len == 1) {
        return arr
    }
    let mid = Math.floor(len / 2)
    return merage(merageSort(arr.slice(0, mid)), merageSort(arr.slice(mid)))
}

function merage(left, right) {
    let result = []
    let li = 0,
        ri = 0,
        llen = left.length,
        rlen = right.length
    while (li < llen && ri < rlen) {
        if (left[li] < right[ri]) {
            result.push(left[li])
            li++
        } else {
            result.push(right[ri])
            ri++
        }
    }
    return li < llen ?
        result.concat(left.slice(li)) :
        result.concat(right.slice(ri))
}

希尔

function hillSort(arr) {
    let gap = Math.floor(arr.length / 2)
    while (gap >= 1) {
        for (let i = gap; i < arr.length; i++) {
            let j, temp = arr[i]
            for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
                arr[j + gap] = arr[j]
            }
            arr[j + gap] = temp
        }
        gap = Math.floor(gap / 2)
    }
    return arr
}

最长递增子序列

function find(arr){
    let len = arr.length
    let countArr = new Array(len).fill(1)
    let max = 1
    for(let i = 1;i < len; i++){
        for(let j = 0;j<i;j++){
            if(arr[j]<arr[i]){
                countArr[i] = countArr[i]>countArr[j]+1?countArr[i]:countArr[j]+1
            }
        }
        max = max>countArr[i]?max:countArr[i]
    }
    return max
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值