this指向的问题归总一下,可分为6种类型:

  1. 全局环境、普通函数(非严格模式)this都指向window
  2. 普通函数(严格模式)指向undefined
  3. 函数作为对象方法及原型链指向的都是上一级对象
  4. 构造函数指向构造的实例
  5. DOM事件中指向触发事件的元素
  6. 箭头函数指向它父级的环境

1.全局环境

全局环境下,this始终指向window,无论是否严格模式。

2.函数环境

2.1普通函数

2.1.1 严格模式下,this指向undefined。

2.1.2 非严格模式下,没有被上一级的对象调用,this默认指向全局对象window

2.2函数作为对象的方法被调用

2.2.1 函数由上一级对象所调用,那么this指向的就是上一级的对象

  1. var obj = {
  2. a:22,
  3. fn:function(){
  4. return this.a;
  5. }
  6. }
  7. obj.fn() // => 22

2.2.2 多层嵌套的对象,内部方法的this指向距离被调用函数最近的对象(window也是对象,其内部函数调用方法的this指向内部对象,而非window)

  1. var obj = {
  2. a:22,
  3. b:{
  4. a:10,
  5. fn:function(){
  6. console.log(this.a)
  7. console.log(this)
  8. }
  9. }
  10. }
  11. obj.b.fn() // => 10
  12. var f = o.b.fn;
  13. f() // => undefined

this始终指向的是最后调用它的对象,也可就是说谁调用它,它就指向谁。当使用obj.b.fn()调用执行函数时,离它最近的对象是b,所以this指向b。第二种方式调用时,虽然函数fn被b所引用,但是却将fn赋值给了变量f,并没有执行,所以this指向了window,而window中没有a属性,故得到undefined。

2.3 setTimeOut或setInterval

2.3.1 对于延迟函数内部的回调函数的this指向全局对象window

2.3.2 可以通过bind方法改变内部函数this指向,详见3.4。

3.原型链调用

3.1 如果该方法存在于一个对象的原型链上,当通过该对象调用这个方法时,this指向的是调用这个方法的对象。

3.2 call和apply:当函数通过Function对象的原型中继承的方法call()和apply()方法调用时,其中函数内部的this值可绑定到call()或apply()方法指定的第一个对象上,如果第一个参数不是对象,js会尝试将它转成对象然后指向它。

3.4 bind():有ES5引入,存在于Function的原型链上,Function.propotype.bind()。通过bind绑定后,函数永远绑定到其第一个参数对象上,无论什么时候调用。

  1. function f(){
  2. console.log(this.a)
  3. }
  4. var g = f.bind({a:'ghh'})
  5. g(); // => ghh
  6. var o = {
  7. a:'指向o',
  8. f:f,
  9. g:g
  10. }
  11. o.f() // => 指向o
  12. o.g() // => ghh

4.构造函数

当一个函数用做构造函数时(通过new创建),它的this指向正在构造的新对象上。构造器默认返回的是this指向的对象,也可以手动返回其他的对象。

  1. function c(){
  2. this.a = 1111;
  3. return {c:"2222"}
  4. }
  5. var o = new c();
  6. console.log(o.a) // => undefined
  7. // 注意:这里的构造器中 如果没有return返回值或者返回的为非对象(包括null和undefined)时,通过new构造出来的实例对象,this指向构造函数;如果有return返回对象时,通过new构造出来的实例对象,this指向返回的对象。

5.在DOM事件中

5.1 作为一个DOM事件处理函数

当函数被用作事件处理函数时,它的this指向触发事件的元素。

5.2 作为一个内联事件处理函数

5.2.1 当代码被内联处理函数直接调用时,他的this指向覆盖监听器所在的DOM元素

5.2.2 当代码被函数包裹内联调用时,等同于普通函数调用,非严格模式下指向window,严格模式下指向undefined,详见2.1。

6.箭头函数

6.1 全局环境下

在全局代码中,箭头函数被设置为全局对象

6.2 this捕捉上下文

箭头函数没有自己的this,而是使用箭头函数所在作用域的this。当在setTimeOut或setInterval中使用箭头函数时,this指向构造函数新生成的对象,情况如同2.3.2。

6.3 箭头函数作为对象方法

箭头函数作为对象方法时,this指向全局对象,而普通函数指向该对象。

6.4 箭头函数中,call()、apply()和bind()方法无效

6.5 this指向固定化

箭头函数的this指向不会根据调用它的方式决定,箭头函数的this永远指向它父级的上下文环境,这种特性有利于封装回调函数。

6.6 箭头函数不适合场景

6.6.1 箭头函数不适合定义对象的方法,因此指向window

6.6.2 需要动态this的时候