【面试题】手写call、apply、bind

区别

相同点:

  • 都可以改变函数的this指向
  • 第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window
  • 都可以利用后续参数传参

不同点:

  • call可以传入多个参数;apply需要传入一个参数对象(数组或类数组);bind可以分开传参,例如:const foo = fn.bind(this, 1, 2); foo(3, 4)
  • call、apply会立即执行,bind不会立即执行,而是返回一个修改this后的函数

实现call

Function.prototype._call = function (thisArg, ...args) {
  // this指向调用_call的函数
  const fn = this
  // 如果要绑定的对象为undefined或null,则默认指向全局对象
  thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window
  // 利用this的隐式绑定规则,将函数的this绑定到指定对象上
  thisArg.fn = fn
  const res = thisArg.fn(...args)
  // 删除新增的fn方法
  delete thisArg.fn

  return res
}

测试:

function foo(a, b) {
  console.log(this.name, a, b)
}

const obj = { name: 'xiaoming' }

foo.call(obj, 20, 30) // xiaoming 20 30
foo._call(obj, 20, 30) // xiaoming 20 30

实现apply

apply和call差别不大,只是传入函数参数的形式不同

完整版:

Function.prototype._apply = function (thisArg, arrArg = []) {
    const fn = this
    thisArg = (thisArg !== undefined && thisArg != null) ? Object(thisArg) : window

    thisArg.fn = fn
    const res = thisArg.fn(...arrArg)
    delete thisArg.fn
    return res
}

简化版:

Function.prototype._apply = function (thisArg, arrArg = []) {
  const fn = this;

  return fn._call(thisArg, ...arrArg);
}

测试:

function foo(a, b) {
    console.log(this.name, a, b)
}

const obj = { name: 'xiaohong' }

foo.apply(obj, [10, 20]) // xiaohong 10 20
foo._apply(obj, [10, 20]) // xiaohong 10 20

实现bind

完整版:

Function.prototype._bind = function (thisArg, ...args) {
    const fn = this
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
    
    // 返回一个新函数作为绑定函数
    return function (...otherArgs) {
        thisArg.fn = fn
        const res = thisArg.fn(...args, ...otherArgs)
        delete thisArg.fn
        return res
    }
}

简化版:

Function.prototype._bind = function (thisArg, ...args) {
  const fn = this;
  
  return function (...otherArgs) {
    return fn._apply(thisArg, args.concat(otherArgs));
  };
};

测试:

function foo(a, b) {
    console.log(this.name, a, b)
}

const obj = { name: 'xiaoli' }

const res = foo.bind(obj, 30)
const res1 = foo._bind(obj, 30)

res(40) // xiaoli 30 40
res1(40) // xiaoli 30 40
posted @ 2024-03-14 18:48  car_Jun  阅读(46)  评论(0)    收藏  举报