this关键字

来源:互联网 发布:复合材料设计软件 编辑:程序博客网 时间:2024/05/21 16:56

在编写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关键字有所帮助。

0 0
原创粉丝点击