this指向总结

107 阅读3分钟

JavaScript 中的 this 依赖于函数的调用方式。所以,想要明白this 的指向问题,还必须先研究函数在JavaScript中是如何被调用的。

1. 作为普通函数调用

非严格模式下指向window对象,严格模式下为undefined。

function func1() {
    console.log(this === window); // true
}
func1();

const func2 = function () {
    console.log(this === window); // true
}
func2();

// 严格模式
function func3() {
    "use strict";
    console.log(this); // undefined
}
func3();

2. 作为对象方法调用

如果一个函数作为一个对象的方法来调用时,this 指向这个对象。

const obj = {
    name: 'doudou',
    func: function() {
        console.log(this === obj); // true
        console.log(this.name); // 'doudou'
    }
};
obj.func();

有些情况下,会丢失绑定对象,指向全局对象

var obj = {
    a: 2,
    foo: foo
};

var bar = obj.foo; // 函数别名

var a = "oops, global"; // a是全局对象的属性

bar(); // "oops, global"
 var name = "The window";
  var object = {
    name: 'My Object',
    getNameFunc: function () {
      console.log(this); // window
      return function () {
          return this.name;
      }
    }
  }
  console.log(object.getNameFunc()()); //  "The window";

匿名函数的 this 永远指向 window

3. 作为构造函数调用

使用new来调用函数时,this指向创建的新对象

function Foo(a) {
    this.a = a;
}

var bar = new Foo(2); // bar和Foo(..)调用中的this进行绑定
console.log( bar.a ); // 2

4. 使用apply、call和bind方法进行调用

这三个方法用于指定函数调用时 this 指向的对象。

  • apply() 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。其中第二个参数可以是 Array 的实例,也可以是 arguments 对象。
  • call() 方法和 apply() 方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call() 方法而言,第一个参数是 this 值没有变化,变化的其余参数都直接传递给函数。换句话说,在使用 call() 方法时,传递给函数的参数 必须逐个列举出来。
  • bind方法通过传入一个对象,返回一个this绑定了新对象的
function foo() {
    console.log( this.a );
}

const obj = {
    a: 2
};

foo.call(obj); // 2  调用foo时强制把foo的this绑定到obj上
foo.apply(obj); // 2
const newFunc = foo.bind(obj);
newFunc() // 2

PS:这四种方式,使用构造器调用模式的优先级最高,然后是 apply 、call和bind调用模式,然后是方法调用模式,然后是普通函数调用模式。

5. 箭头函数中的this

不会使用上文的四条标准的绑定规则, 而是根据当前的词法作用域来决定this, 具体来说,箭头函数会继承外层函数,调用的 this 绑定( 无论 this 绑定到什么),没有外层函数,则是绑定到全局对象(浏览器中是window)。 这其实和 ES6 之前代码中的 self = this 机制一样。

function foo() {
    // 返回一个箭头函数
    return (a) => {
        // this继承自foo()
        console.log( this.a );
    };
}

var obj1 = {
    a: 2
};

var obj2 = {
    a: 3
}

var bar = foo.call( obj1 );
bar.call( obj2 ); // 2,不是3!

解析:
foo()内部创建的箭头函数会捕获调用时foo()的this。  
由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改(new也不行)

题目一:

var num = 1;
var myObject = {
    num: 2,
    add: function() {
        this.num = 3;
        (function() {
            console.log(this.num); // 这里的this指向window
            this.num = 4;
        })();
        console.log(this.num); // 这里的this指向myObject
    },
    sub: function() {
        console.log(this.num) // 这里的this指向myObject
    }
}
myObject.add(); // 1 3
console.log(myObject.num); // 3
console.log(num); // 4

var sub = myObject.sub;
sub(); //4

参考:github.com/yygmind/blo…