前端常见手写题

33 阅读2分钟

1.Promise

class Promise {
  constructor(fn) {
    // 三个状态
    this.state = 'pending'
    this.value = undefined
    this.reason = undefined
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'
        this.value = value
      }
    }
    let reject = value => {
      if (this.state === 'pending') {
        this.state = 'rejected'
        this.reason = value
      }
    }
    // 自动执行函数
    try {
      fn(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  // then
  then (onFulfilled, onRejected) {
    switch (this.state) {
      case 'fulfilled':
        onFulfilled(this.value)
        break
      case 'rejected':
        onRejected(this.value)
        break
      default:
    }
  }
}

2.new

function newOperator (constructor, ...args) {
  // 创建一个空的对象,并链接该对象到构造函数的原型
  const obj = Object.create(constructor.prototype);

  // 将构造函数的作用域赋给新对象(即绑定构造函数内部的this)
  const result = constructor.apply(obj, args);

  // 如果构造函数返回一个对象,则返回这个对象
  // 注意,如果构造函数返回的是一个非原始类型的值,则无视它
  return result instanceof Object ? result : obj;
}
function Person (name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function () {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

const person = newOperator(Person, 'Alice', 30);
person.greet();
console.log("🚀 ~ person:", person)

3.call,参数是以逗号分开的

//实现一个 call 函数
Function.prototype.myCall = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error');
  }
  context = context || global;
  // 将当前函数(被.myCall调用的函数)作为context的一个临时属性
  context.fn = this;
  //slice(1) 方法去掉第一个参数,因为在 myCall 函数中第一个参数是指定的 context,后面的参数才是传递给目标函数的参数。
  let args = [...arguments].slice(1);
  console.log("🚀 ~ ...arguments:", [...arguments].slice(1), args)
  let result = context.fn(...args);
  delete context.fn;
  return result;
}
// 测试函数
function greet (greeting, name,age) {
  console.log(greeting, name,age);
}

// 使用自定义的 myCall 方法,并且传递参数
greet.myCall(null, 'Hello', 'Alice','18'); // 打印:['Hello', 'Alice']

4.apply,参数是一个数组

Function.prototype.myApply = function (context, argsArray) {

  if (typeof this !== 'function') {

    throw new TypeError('Error');

  }

 

  context = context || global;

 

  const fnKey = Symbol(); // 创建唯一键,防止属性冲突

  context[fnKey] = this;

 

  let result;

  if (Array.isArray(argsArray)) {

    result = context[fnKey](...argsArray); // 使用展开语法调用函数

  } else {

    result = context[fnKey](); // 如果没有提供参数或者参数为null/undefined,直接调用函数

  }

 

  delete context[fnKey]; // 删除添加的属性

 

  return result;

}

  


// 示例

function greet(greeting, name) {

  console.log(greeting, name);

}

  


const person = { name: 'John' };

greet.myApply(person, ['Hello', 'Alice']);

5.bind类似call,但返回的是函数

// 思路:类似call,但返回的是函数
Function.prototype.mybind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  let _this = this
  let arg = [...arguments].slice(1)
  return function F () {
    // 处理函数使用new的情况
    if (this instanceof F) {
      return new _this(...arg, ...arguments)
    } else {
      return _this.apply(context, arg.concat(...arguments))
    }
  }
}

三种的区别

image.png 6.递归拷贝


function deepClone(obj) {
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return copy
}