JS中的this

127 阅读3分钟

JavaScript 中的 this 有如下 5 种使用场景:

  1. 箭头函数 () => {}
  2. new 调用构造函数 new F()
  3. 显式绑定 call/apply/bind
  4. 隐式绑定 obj.foo()
  5. 默认绑定 foo()

箭头函数中的this

箭头函数没有自己的执行上下文,内部的 this 代表函数创建时候所在的词法作用域中的 this,与调用方式无关,例如:

const obj = {
  name: 'david',
  say: () => {
    console.log(this.name)
  },
}
obj.say()
const say = obj.say
say()

由于是箭头函数,所以 this 就是根据词法作用域往上查找,找到了全局作用域,所以打印两个 undefined,而如果把箭头函数改成普通的 function,那么将会打印一个 david 一个 undefined

总结:箭头函数的 this 与如何调用无关,只与创建时候的词法作用域有关。

构造函数中的this

所有的 JavaScript 函数都可以使用 new 操作符来创建新对象,此时该函数被称为构造函数。构造函数中的 this 就代表被创建的这个对象,例如:

function Person() {
  this.age = 10
  setTimeout(() => {
    console.log(this.age) 
  }, 1000)
}
var p = new Person()

由于使用了 new 操作符,Person 函数中的 this 会被绑定到新创建的对象上,由于 setTimeout 回调是箭头函数,根据上面讲的箭头函数中的 this 是创建时词法作用域中的 this,也就是函数 Person 中的 this,因此打印 10。但是如果把 setTimeout 回调的箭头函数改成 function 的话,结果就不一样了,会输出 undefined。

总结:构造函数中的 this 指向被创建的对象。

call/apply/bind中的this

call 和 apply 两个函数能够显式设置函数 this 的值,例如下面的代码:

var obj = {}
var add = function (x, y) {
	this.val = x + y
}
add.apply(obj, [2, 8])
console.log(obj.val)

因为 this 被指定为 obj 对象,所以 this.val 就相当于 obj.val,打印 10。call 函数的用法是一样的,只是函数的参数不是以数组的形式传,而是一个个传:

add.call(obj, 2, 8)
console.log(obj.val)

另外,如果 call 和 apply 的第一个参数为空的话,默认是全局对象。

而 bind 和 call/apply 的区别在于,在绑定 this 到对象参数的同时:

  1. call/apply 将立即执行该函数
  2. bind 不执行函数,返回一个可供执行的新函数

例如上面的代码可用 bind 改写为:

const f = add.bind(obj)
f(2, 8)
console.log(obj.val)

总结:call/apply/bind 可以指定函数中的 this,call/apply 立即执行,bind 返回新函数。

隐式绑定this

执行函数的时候,先看函数前面是否有点,如果有点的话,那么点前面是谁,this 就是谁,这就叫隐式绑定,没有点的话,在非严格模式下,this 就是 window,严格模式下是 undefined。

var name = 'global'
function fn() {
  console.log(this)
}
let obj = {
  name: 'obj',
  fn: fn
}
fn()
obj.fn()

所以默认情况下,在浏览器中会打印 global 和 obj。

总结:如果函数前面有点,那么点的前面是谁,this 就是谁。

全局环境下的this

在浏览器中,全局环境就是 window 对象,全局执行上下文中的 this 就指的是 window 对象,例如:

var x = 10
var f = function(){
    console.log(this.x)
}
f()

函数 f 内的 this 指向全局对象,所以输出 10。值得注意的是,setTimeout 的回调函数就是被全局所调用的,因为 setTimeout 会开启了一个新的执行环境。

总结:浏览器全局执行上下文中的 this 指向 window 对象。