当前位置主页 > 资料库 > 前端教程 > 掌握javascript的“this”关键字

掌握javascript的“this”关键字

05-27

在编写javascript代码的时候,我们经常需要使用“this”关键字。“this”关键字在不同的上下文中所代表的对象是不同的。在这篇文章中,我们将详细的讲解“this”关键字在不同上下文中的含义和一些常见问题及其解决方案。

常见问题

在获取方法中使用this关键字

使用this关键字最常见的错误是将一个对象的方法分配给一个变量,并希望this关键字指向原来的对象。来看下面的例子:

var car = {
  brand: "Nissan",
  getBrand: function(){
    console.log(this.brand);
  }
};
 
var getCarBrand = car.getBrand;
 
getCarBrand();   // 输出: undefined                              
                            

上面的代码使用getCarBrand变量来接收car.getBrand()的引用,实际上得到的只是另一个指向getBrand()本身的引用。我们指定函数的调用者决定上下文,这里的调用者是getCarBrand(),这是一个简单的函数调用。

要证明getCarBrand变量并不指向任何的函数,可以简单的使用alert(getCarBrand);,你在控制台中可以看到输出的是:

function(){
  console.log(this.brand);
}                              
                            

getCarBrand保存的只是一个普通的函数,而不是car对象的一个函数。因此,this.brand会被翻译为window.brand。所以得到的结果是undefined

那么我们要如何解决这个问题呢?如果我们需要this指向原来的对象,我们需要明确的使用bind()方法将getBrand()绑定到car对象上。然后在将它赋值给getCarBrand变量。

var getCarBrand = car.getBrand.bind(car);
getCarBrand();   // 输出: Nissan                              
                            

通过上面的方法,我们可以得到正确的结果,因为我们重新定义了我们需要的上下文。

在回调函数中使用this关键字

另一个容易出错的地方是我们将一个带有this关键字的方法作为回调函数来使用。例如:

<button id="btn" type="button">Get the car's brand</button>
 
var car = {
  brand: "Nissan",
  getBrand: function(){
    console.log(this.brand);
  }
};
 
var el = document.getElementById("btn");
el.addEventListener("click", car.getBrand); 
//输出:undefined                             
                            

虽然我们使用的是car.getBrand,事实上我们得到的egetBrand()函数是附加在button对象上的方法。

这里发生的事情和上面的例子相似,不同的是现在car.getBrand不是被明确的赋值,而是隐含的赋值。所得到的结果是一样的,一个绑定到button上的普通函数。

换句话来讲,我们在一个对象上执行一个方法,与这个对象原理定义的方法是不一样的。this关键字不在指向对象本身,而是指向调用对象的那个方法。

对于上面的例子来说,我们在按钮上执行car.getBrand方法,而不是在car对象上。因此,this关键字指向的是el(按钮元素),而不是car对象。

如果希望this关键字指向原来的对象,和上面一样,我们需要明确的使用bind()方法在car对象上绑定getBrand()方法。

el.addEventListener("click", car.getBrand.bind(car));                              
                            
在闭包中使用this关键字

在闭包中使用this关键字也是容易发生错误的地方。看下面的例子:

var car = {
  brand: "Nissan",
  getBrand: function(){
    var closure = function(){
      console.log(this.brand);
    };
    return closure();
  }
};
 
car.getBrand();   // 输出: undefined                               
                            

这里得到的结果是“undefined”,因为闭包(内部函数)不接收外部函数的this变量。最终的结果是this.brand等于window.brand,因为在内部函数中,this关键字是被绑定到全局对象上的。

要修正这个问题,我们需要将this关键字绑定到getBrand()方法上。

var car = {
  brand: "Nissan",
  getBrand: function(){
    var closure = function(){
      console.log(this.brand);
    }.bind(this);
    return closure();
  }
};
 
car.getBrand();   // 输出: Nissan                              
                            

这个绑定相当于car.getBrand.bind(car)

另一个修正闭包的方法是将this值保存在一个变量中,这样可以避免不必要的变化。

var car = {
  brand: "Nissan",
  getBrand: function(){
    var self = this;
    var closure = function(){
      console.log(self.brand);
    };
    return closure();
  }
};
 
car.getBrand();   // 输出: Nissan                               
                            

ECMAScript 6中的解决方案

在上面的例子中我们看到了使用this关键字应该注意的地方。在ECMAScript 6中我们可以类似上面那样使用this关键字,但是ECMAScript 6为我们提供了箭头操作符,使代码可以更加优雅和清晰。

箭头操作符不是由function关键字创建的,而是所谓的“fat arrow”操作符(=>)。和常规的函数不同,箭头操作符从它们的封闭作用域中获取this值。箭头绑定的函数不能够被重写,即使是通过new操作符。

下面来看看箭头操作符是如何替代var self = this;声明的。

var car = {
  brand: "Nissan",
  getBrand: function(){
    // the arrow function keeps the scope of "this" lexical
    var closure = () => {   
      console.log(this.brand);
    };
    return closure();
  }
};
 
car.getBrand();   // 输出: Nissan                              
                            

关于this需要记住的东西

当你遇到this关键字的时候,和js的其它功能模块一样,如果你了解它的底层原理和各种情况的处理方法,那么你就会更加有信心去理解和使用它。下面吗让我们来简单总结一下使用this关键字需要注意的地方。

  • this关键字在下面的情况下总是指向全局对象:
    • 在最外层的上下文中,在任何函数块之外
    • 在函数中,但不是任何对象的方法
    • 在函数中,但不是对象构造函数
  • 当一个函数被作为父元素对象一个属性调用的时候,this指向父元素。
  • 当使用call()apply()bind()方法来调用函数的时候,this指向这些函数的第一个参数。如果第一个参数是null或不是一个对象,this指向全局对象。
  • 当使用new操作符去调用一个函数的时候,this指向新创建的对象。
  • 当使用箭头操作符(ECMAScript 6)的时候,this依赖于词法作用域并指向其父元素对象。

记住上面的简单规则,我们就可以知道this究竟是指向什么对象。如果不是我们需要的结果,我们可以使用相应的方法来修正它。

小结

JavaScript的this关键字是一个比较复杂的概念,但是只要你多想多练就一定能够掌握它。希望这篇文章对你掌握this关键字有所帮助。

Previous:
上一篇:使用CSS Blend Modes制作跨浏览器的文字遮罩效果
Next:
下一篇:10个最好的jQuery移动手机设备插件
返回顶部