JavaScript `this`参考


在JavaScript中,每个函数都有this引用在声明它自动创建。该参考颇为相似, this在其他基于类的语言如Java或C#参考(JavaScript是一种基于原型的语言,并没有“阶级”的概念): 它指向哪个对象有时调用的函数 (该对象称为上下文 )。但是,在JavaScript中, 函数内部的this引用可以绑定到不同的对象,具体取决于调用函数的位置 。以下是JavaScript中this绑定的5个基本规则:

规则1

在全局范围中调用函数时, this引用默认绑定到全局对象 (浏览器中的window或Node.js中的global )。例如:

function foo() {
  this.a = 2;
 }

 foo();
 console.log(a); // 2

注意:如果在严格模式下声明上面的foo()函数,那么在全局范围内调用此函数, this将是undefined并且赋值this.a = 2将抛出Uncaught TypeError异常。

规则2

我们来看下面的例子:

function foo() {
  this.a = 2;
 }

 var obj = {
  foo: foo
 };

 obj.foo();
 console.log(obj.a); // 2

显然,在上面的代码片段中, foo()函数被调用, _上下文_是obj对象,现在this引用绑定到obj 。因此,当使用上下文对象调用函数时, this引用将绑定到此对象。

规则3

.call.apply.bind都可以在调用点使用显式绑定this 。使用.bind(this)是你可以在很多React组件中看到的东西。

var foo = function() {
  console.log(this.bar)
 }

 foo.call({ bar: 1 }) // 1

这是一个快速的例子,说明如何使用每个绑定this

  • fn.call(thisObj, fnParam1, fnParam2) .call()fn.call(thisObj, fnParam1, fnParam2)
  • .apply()fn.apply(thisObj, [fnParam1, fnParam2])
  • .bind()const newFn = fn.bind(thisObj, fnParam1, fnParam2)

规则4

function Point2D(x, y) {
  this.x = x;
  this.y = y;
 }

 var p1 = new Point2D(1, 2);
 console.log(p1.x); // 1
 console.log(p1.y); // 2

您必须注意的是使用new关键字调用的Point2D函数,并且this引用绑定到p1对象。因此,当使用new关键字调用函数时,它将创建一个新对象,并且this引用将绑定到此对象。

注意:当您使用new关键字调用函数时,我们也将其称为构造函数

规则5

的JavaScript确定的值this在运行时,基于所述当前上下文。所以this有时会指向你期望的东西。

考虑这个带有一个名为makeSound()的方法的Cat类示例,遵循规则4(上面)中的模式,带有构造函数和new关键字。

var Cat = function(name, sound) {
    this.name = name;
    this.sound = sound;
    this.makeSound = function() {
        console.log( this.name + ' says: ' + this.sound );
    };
 }
 var kitty = new Cat('Fat Daddy', 'Mrrooowww');
 kitty.makeSound(); // Fat Daddy says: Mrrooowww

现在让我们试着给猫一个方法来annoy()人们通过重复他的声音100次,每半秒一次。

var Cat = function(name, sound) {
    this.name = name;
    this.sound = sound;
    this.makeSound = function() {
        console.log( this.name + ' says: ' + this.sound );
    };
    this.annoy = function() {
        var count = 0, max = 100;
        var t = setInterval(function() {
            this.makeSound(); // <-- this line fails with `this.makeSound is not a function`
            count++;
            if (count === max) {
                clearTimeout(t);
            }
        }, 500);
    };
 }
 var kitty = new Cat('Fat Daddy', 'Mrrooowww');
 kitty.annoy();

这不起作用,因为在setInterval回调中我们创建了一个具有全局范围的新上下文,所以this不再指向我们的kitty实例。在Web浏览器中, this将指向Window对象,该对象没有makeSound()方法。

有几种方法可以使它工作:

1)创建新的上下文之前,分配this名为局部变量me ,或self ,或任何你想将它命名,并使用回调内部的变量。

var Cat = function(name, sound) {
    this.name = name;
    this.sound = sound;
    this.makeSound = function() {
        console.log( this.name + ' says: ' + this.sound );
    };
    this.annoy = function() {
        var count = 0, max = 100;
        var self = this;
        var t = setInterval(function() {
            self.makeSound();
            count++;
            if (count === max) {
                clearTimeout(t);
            }
        }, 500);
    };
 }
 var kitty = new Cat('Fat Daddy', 'Mrrooowww');
 kitty.annoy();

2)同ES6就可以避免分配this通过使用箭头功能,其结合本地变量this到它的限定的周围的代码的情况下。

var Cat = function(name, sound) {
    this.name = name;
    this.sound = sound;
    this.makeSound = function() {
        console.log( this.name + ' says: ' + this.sound );
    };
    this.annoy = function() {
        var count = 0, max = 100;
        var t = setInterval(() => {
            this.makeSound();
            count++;
            if (count === max) {
                clearTimeout(t);
            }
        }, 500);
    };
 }
 var kitty = new Cat('Fat Daddy', 'Mrrooowww');
 kitty.annoy();

更多JavaScript教程

学习更多JavaScript教程