this 绑定规则—浅谈几种情形下 this 的指向

看这篇文章之前,需要搞明白,this 是在函数调用时绑定的,而不是书写函数时绑定的

下面谈到了几种情形下,this 的指向问题,即 this 被绑定到了哪里

默认绑定

function foo () {
  console.log(this.a)
}
var a = 2
foo() // 2

上面代码片段中的 this 绑定到了全局对象

隐式绑定

function foo () {
  console.log(this.a)
}
var obj = {
  a: 2,
  foo: foo
}
obj.foo() // 2

上面 foo 的调用有上下文,this 绑定到了 obj 上

实际上,上文讲到的第一种情形(默认绑定)也可以看做隐式绑定

function foo () {
  console.log(this.a)
}
var a = 2
foo() // 2
// 等同于
window.foo() // 2

上面 foo 的上下文可看成全局对象 window,所以 this 绑定到了 window 上

对象属性引用链中只有最后一层会影响调用位置

function foo () {
  console.log(this.a)
}
var obj2 = {
  a: 42,
  foo: foo
}
var obj1 = {
  a: 2,
  obj2: obj2
}
obj1.obj2.foo() // 42

下面的例子比较特殊

function foo () {
  console.log(this.a)
}
var obj = {
  a: 2,
  foo: foo
}
var bar = obj.foo // 函数别名!
var a = "oops, global" // a 是全局对象的属性
bar() // "oops, global"

因为此处的 bar 是对全局函数 foo 的一个引用,上下文并非 obj,所以 this 绑定到了全局对象上,这种情况被称为隐式丢失

下面的例子是同样的道理

function foo () {
  console.log(this.a)
}
function doFoo (fn) {
  // fn 其实引用的是 foo
  fn() // <-- 调用位置!
}
var obj = {
  a: 2,
  foo: foo
}
var a = "oops, global" // a 是全局对象的属性
doFoo(obj.foo) // "oops, global"

显示绑定

可以使用 call、apply、bind 等方法来达到显式绑定的目的

function foo () {
  console.log(this.a)
}
var obj = {
  a:2
}
foo.call(obj) // 2

上面代码的 this 通过 call 方法绑定到了 obj 上

JavaScript 语言和宿主环境中有许多内置函数都提供了一个可选的参数,用于指定回调函数中 this 的指向,比如

function foo () {
  console.log(this.id)
}
var obj = {
  id: "awesome"
}
// 调用 foo 时把 this 绑定到 obj
[1, 2, 3].forEach(foo, obj)
// 1 awesome 2 awesome 3 awesome

new 绑定

function foo () {
  this.a = 2
  this.b = 3
}
var bar = new foo()
console.log(bar.a, bar.b) // 2 3

使用 new 来调用 foo 时,会构造一个新对象并把它绑定到 foo 调用中的 this 上

除特殊说明外本人博客均属原创,转载请注明出处:http://blog.johnhan.cn/blog_1074.html
京ICP备19044523号-1