Javascript中的bind

引子:模拟bind函数

实现一个$bind函数模拟bind函数。

// no-log
Function.prototype.$bind = function (obj) {
  let self = this
  return function () {
    self.apply(obj, arguments)
  }
}

下面进行测试

// log
let obj1 = { id: 0 }
let obj2 = { id: 1 }
function sayId() {
  console.log(this.id)
}
sayId.bind(obj1)() // ES5实现的bind
sayId.$bind(obj2)() // 我们自定义的$bind

很好,达到了我们想要的效果。

有何不同

然后探究我们的$bind和真实的bind有何差异。下面两部分代码分别使用了$bindbind,代码的其余部分完全相同,但是其输出却不同。

// log
function foo(something) {
  this.a = something
}
let obj1 = {}
let fooWithBind = foo.$bind(obj1) // 这里不同
let obj2 = new fooWithBind(999)

console.log(obj1.a)
console.log(obj2.a)
// log
function foo(something) {
  this.a = something
}
let obj1 = {}
let fooWithBind = foo.bind(obj1) // 这里不同
let obj2 = new fooWithBind(999)

console.log(obj1.a)
console.log(obj2.a)

原因:ES5内置的bind更加复杂,主要体现在 this 的绑定的优先级上:它会判断硬绑定函数是否被new调用,如果是的话就会使用新创建的this代替硬绑定的this

总结

通过自定义一个残缺的bind函数,回顾了判断this指向的相关知识点。可按照如下步骤进行。

  1. 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。 如:var bar = new foo()
  2. 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是 指定的对象。 如:var bar = foo.call(obj2)
  3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。如:var bar = obj1.foo()
  4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象 如:var bar = foo()

参考

[1]你不知道Javascript P94

posted @ 2020-09-21 00:55  oceans-pro  阅读(130)  评论(0编辑  收藏  举报