每天亿遍---最全前端手写代码题

本文总结了前端面试中常见的手写代码题目,包括Promise、jsonp、instanceof、call、apply、bind、new、ES5继承、防抖和节流等。通过每日练习,帮助开发者熟悉并掌握这些核心概念,提升面试自信。

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

前端面试手写代码题实在是我的一个弱项,加上面试时紧张会写不出来,下定决心要战胜它
只要把它背的像身份证号码一样熟,面试就不再怕了
所以总结了一下网上经典的、自己面试遇到过的手写代码题
每天亿遍~~ 早日战胜手写代码题
欢迎点赞收藏关注,后续会继续补充

手写Promise、Promise.all、Promise.race

包括then、catch、all、race

/**
 * @description 手写Promise
 */

class MyPromise {
  state = 'pending' // 状态 'pending' 'fulfilled' 'rejected'
  value = undefined  // 成功后的值
  reason = undefined // 失败后的值

  resolveCallbacks = [] // pending状态下,成功的回调
  rejectCallbacks = [] // pending状态下,失败的回调


  constructor(fn){
    const resolveHandler = (value) => {
      if(this.state === 'pending'){
        this.state = 'fulfilled'
        this.value = value
        this.resolveCallbacks.forEach(fn => fn(this.value))
      }
    }

    const rejectHandler = (reason) => {
      if(this.state === 'pending'){
        this.state = 'rejected'
        this.reason = reason
        this.rejectCallbacks.forEach(fn => fn(this.reason))
      }
    }

    try {
      fn(resolveHandler, rejectHandler)
    } catch(err) {
      rejectHandler(err)
    }
  }

  then(fn1, fn2){
    // 当 pending状态下, fn1 和 fn2 会被存储到callbacks中
    fn1 = typeof fn1 === "function" ? fn1 : (v) => v
    fn2 = typeof fn2 === "function" ? fn2 : (e) => e

    if(this.state === 'pending'){
      const p1 = new MyPromise((resolve,reject) => {
        this.resolveCallbacks.push(()=>{
          try {
            const newValue = fn1(this.value)
            resolve(newValue)
          } catch(err){
            reject(err)
          }
        })

        this.rejectCallbacks.push(() => {
          try {
            const newReason = fn2(this.Reason)
            reject(newReason)
          } catch(err){
            reject(err)
          }
        })
      })
      return p1
    }

    if(this.state === 'fulfilled'){
      const p1 = new MyPromise((resolve,reject) => {
        try {
          const newValue = fn1(this.value)
          resolve(newValue)
        } catch(err){
          reject(err)
        }
      })
      return p1
    }

    if(this.state === 'rejected'){
      const p1 = new MyPromise((resolve,reject) => {
        try {
          const newReason = fn2(this.reason)
          reject(newReason)
        } catch(err){
          reject(err)
        }
      })
      return p1
    }

  }
 
  // 就是then的语法糖,简单模式
  catch(fn) {
    return this.then(null, fn)
  }
}

MyPromise.resolve = function(value) {
  return new MyPromise((resolve,reject) => {
    resolve(value)
  })
}

MyPromise.reject = function(reason) {
  return new MyPromise((resolve,reject) => {
    reject(reason) 
  })
}

MyPromise.all = function (promiseList = []) {
  const p1 = new MyPromise((resolve,reject) => {
    const result = []
    const length = promiseList.length
    let resolvedCount = 0

    promiseList.forEach((p)=>{
      p.then(data => {
        result.push(data)
        resolvedCount++ // 同理,resolvedCount 必须在then里进行++
        // 这里不能用forEach 的 index来判断 index === length - 1,因为forEach不是一个异步循环,index会一下子增加到最大,而promiseList中的每一个promise还不一定执行完
        if(resolvedCount === length){
          // 已经遍历到最后一个promise
          resolve(result)
        }
      }).catch(err => {
        reject(err)
      })
    })
  })
  return p1
}

MyPromise.race = function(promiseList = []) {
  let resolved = false // 标记
  const p1 = new MyPromise((resolve,reject) => {
    promiseList.forEach(p => {
      p.then(data => {
        if(!resolved){
          resolve(data)
          resolved = true
        }
      }).catch((err) => {
        reject(err)
      })
    })
  })
  return p1
}



// 测试
let p4 = new MyPromise((resolve,reject) => {
  setTimeout(() =>{
    resolve(100)
  },1000)
})

let p2 = new MyPromise((resolve,reject) => {
  resolve(666)
})

MyPromise.all([p4,p2]).then((res) => {
  console.log(res)
})

console.log(p1)
p1.then((res) => {
  console.log(res)
})

p2.then((val) => {
  console.log(val)
})

手写jsonp

(function (global) {
  function jsonp (url, params, callback) {
    let queryStringArr = [];
    for (var k in params) {
      queryStringArr.push(`${k}=${param[k]}`);
    }

    let random = Math.random().toString().replace('.', '');
    let callbackFunctionName = 'jsonp_' + random;
    queryStringArr.push(`callback=${callbackFunctionName}`);

    let script = document.createElement('script');
    script.src = url + '?' + queryStringArr.join('&');
    document.body.appendChild(script);

    global[callbackFunctionName] = function (param) {
      callback(param);
      document.body.removeChild(script);
    };
  }

  global.jsonp = jsonp;
})(window);

手写instanceof

function myInstance(left, right) {
    var proto = left.__proto__;
    var prototype = right.prototype;

    if (proto === null) {
        return false;
    } else if (proto === prototype) {
        return true;
    } else {
        return myInstance(proto, right);
    }
}
// test
var a = {};
console.log(myInstance(a,Array)); //false
console.log(myInstance({}, Object)) //true

手写call

Function.prototype.myCall = function(thisArg, ...args) {
const fn = Symbol('fn')        // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window    // 若没有传入this, 默认绑定window对象
thisArg[fn] = this              // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg[fn](...args)  // 执行当前函数
delete thisArg[fn]              // 删除我们声明的fn属性
return result                  // 返回函数执行结果
}
//测试
foo.myCall(obj)

手写apply

Function.prototype.myCall = function(thisArg, args) {
const fn = Symbol('fn')        // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
thisArg = thisArg || window    // 若没有传入this, 默认绑定window对象
thisArg[fn] = this              // this指向调用call的对象,即我们要改变this指向的函数
const result = thisArg[fn](...args)  // 执行当前函数
delete thisArg[fn]              // 删除我们声明的fn属性
return result                  // 返回函数执行结果
}
//测试
foo.myCall(obj, [])

手写bind

Function.prototype.myBind = function(obj){
  // 从arguments第2个开始是参数
  var args = Array.prototype.slice.call(arguments,1)
  var fn = this
  // 返回一个绑定好的方法
  return function(){
    var newArgs = Array.prototype.slice.call(arguments)
    // 可能存在foo.bind(obj,args)(newArgs),所以要把两个参数拼在一起
    fn.apply(obj, args.concat(newArgs))
  }
}

手写new

let newMethod = function(Parent, ...rest){
  // 1、以构造器的prototype属性为原型,创建新对象
  let child = Object.create(Parent.prototype)
  // 2、将this(也就是上一句中的新对象)和调用参数传给构造器,执行
  let result = Parent.call(child, ...rest)
  // 3、如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象
  return result instanceof Object ? result : child
}

let Parent = function (name, age) {
  this.name = name;
  this.age = age;
};

手写ES5继承

ES5继承需要使用组合继承 既要继承属性又要继承方法

// 父类
function Animal(name){
  this.name = name
}

Animal.prototype.showName = function(){
  console.log("这个动物的名字是"+this.name)
}

// 子类
function Dog(name,color){
  Animal.call(this,name) // 只能继承属性
  this.color = color
}

Dog.prototype = new Animal() // 原型继承
Dog.prototype.constuctor = Dog

let d1 = new Dog('doge','white')
console.log(d1) // Dog {name: "doge", color: "white"}
d1.showName() // 这个动物的名字是doge

手写防抖debounce

  function debounce(func, delay) {
  let timeout
  return function() {
    clearTimeout(timeout) // 如果持续触发,那么就清除定时器,定时器的回调就不会执行。
    timeout = setTimeout(() => {
      func.apply(this, arguments)
    }, delay)
  }
}

手写节流throttle

    function throttle(func, delay){
    let run = true
    return function(){
      if(!run){
        return  
      } else {
        run = false
        func.apply(this, arguments)
        setTimeout(function(){
          run = true
        },delay)
      }
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值