Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

手写 call、apply、bind #41

Open
18888628835 opened this issue Jun 10, 2021 · 0 comments
Open

手写 call、apply、bind #41

18888628835 opened this issue Jun 10, 2021 · 0 comments

Comments

@18888628835
Copy link
Owner

手写 call、apply、bind

call

call的作用就一句话:call 能够显式地绑定函数中的 this并调用函数。

参数

function.call(thisArg, arg1, arg2, ...)

例子

function foo(){
  console.log(this.age)
}
const obj={age:'18'}
foo() // undefined
foo.call(obj) // 18

上面的例子中,call 显示地将 obj 绑定到 foo 函数中的 this 上,所以能够打印出 obj 的属性 age

了解原理后,我们直接开写

Function.prototype.likeCall=function (thisArg,...args){
  thisArg.func=this //这里的 this 是 foo.call 中的 foo 函数,谁调用call,this 就是谁
  const result=thisArg.func(...args)
  delete thisArg.func //记得删除
  return result
}

有了 ES6的语法加持,我们很快就可以实现。

apply

apply 跟 call 的唯一区别就是apply 第二个参数接收一个数组

参数

function.apply(thisArg, arrayArg)

我们直接改写就行

Function.prototype.likeApply=function (thisArg,args){
  thisArg.func=this //这里的 this 是 foo.apply 中的 foo 函数,谁调用apply,this 就是谁
  const result=thisArg.func(...args)
  delete thisArg.func //记得删除
  return result
}

bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。——MDN

示例

this.x = 9;    // 在浏览器中,this 指向全局的 "window" 对象
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的

// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
  • 第一种方法
    诸如 call 的实现,只是需要返回一个函数
Function.prototype.likeBind=function (thisArg,...args1){
  thisArg.func=this
  return (...args2)=>{
    thisArg.func(...args1,...args2)
    delete thisArg.func
  }
}

这样基于柯里化的方式,不但可以在绑定bind调用时传递第二个参数,还可以在调用后加参数。

const boy={name:'qiuyanxi'}
function foo(args){
  console.log(this.name)
  console.log(args)
}
foo.likeBind(boy,'123')()
foo.likeBind(boy)('123')
// 'qiuyanxi'
// '123'

只是这个方法缺点也很显而易见,当没调用 bind方法返回的函数时,func 存在于传递的 thisArg 中。

  • 第二种方法
    我们使用bind的时候都是采用function.bind(obj)的方式,这样就能够让obj变成fn函数中的this,所以我们可以把obj当成call参数直接传给fn,不就可以实现bind了吗?
Function.prototype.likeBind=function (asThis,...args){
   const fn=this //这里是把取到调用bind的fn
   return (...args1)=>{
     return fn.likeCall(asThis,...args,...args1)
   }
}
  • 第三种方法
    第三种方法采用 es5来写,实际原理是一样的,这里顺便套用一下之前写好的 likeCall 和 likeApply
Function.prototype.likeBind = function () {
  var fn = this;
  var args=Array.prototype.slice.likeCall(arguments)//由于 arguments 没有 Array 的原型,所以用这种方式调用 slice 方法
  var asThis = args[0];//获取到要绑定的this
  var args1 = args.slice(1);//获取到参数1
  return function () {
    var args2 = Array.prototype.slice.likeCall(arguments);//获取到参数2
    return fn.likeApply(asThis, args1.concat(args2));
  };
};

完成了~

enjoy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant