【译】javascript的this关键词理解

一直以来,javascript里边的this都是一个很难理解的东西,以前看的最多的就是阮一峰老师关于this的理解:javascript

http://www.ruanyifeng.com/blo...html

http://www.ruanyifeng.com/blo...java

今天在留言区发现了一国外大神关于this的理解,借助翻译工具读了一下原文,相对来讲是最好的关于理解this的文章,就翻译了一下,也算是记录一下。编程

JavaScript的一个经常使用特性是“this”关键字,但它也经常是该语言中最使人困惑和误解的特性之一。“this”究竟是什么意思?它是如何决定的?小程序

本文试图澄清这种困惑,并以一种清晰的方式解释这个问题的答案。app

“this”关键字对于那些用其余语言编程的人来讲并不新鲜,并且它一般引用在经过类的构造函数实例化类时建立的新对象。例如,若是我有一个类Boat(),它有一个方法moveBoat(),当在moveBoat()方法中引用“this”时,咱们其实是在访问新建立的Boat()对象。函数

在JavaScript中,当使用“new”关键字调用函数构造函数时,函数构造函数中也有这个概念,可是它不是唯一的规则,并且“this”经常能够引用来自不一样执行上下文的不一样对象。若是您不熟悉JavaScript的执行上下文,我建议您阅读我关于这个主题的另外一篇文章(本人注:文章找不到了)。谈得够多了,让咱们来看一些JavaScript例子:工具

// 全局做用域

foo = 'abc';
alert(foo); // abc

this.foo = 'def';
alert(foo); // def

不管什么时候在全局上下文中使用关键字“this”(而不是在函数中),它老是指向全局对象。如今让咱们看看函数中“this”的值:this

var boat = {
    size: 'normal',
    boatInfo: function() {
        alert(this === boat);
        alert(this.size);
    }
};

boat.boatInfo(); // true, 'normal'

var bigBoat = {
    size: 'big'
};

bigBoat.boatInfo = boat.boatInfo;
bigBoat.boatInfo(); // false, 'big'

那么上面的“this”是如何肯定的呢?咱们能够看到一个对象boat,它有一个属性size和一个方法boatInfo()。在boatInfo()中,若是该对象的值是实际的boat对象,它将发出警报,并警告该对象的size属性。所以,咱们使用boat.boatInfo()调用函数,能够看到这是boat对象,而且boat的size属性是正常的。spa

而后咱们建立另外一个对象bigBoat,它的size属性为big。然而,bigBoat对象没有一个boatInfo()方法,所以咱们使用bigBoat从boat复制该方法。boatInfo = boat.boatInfo。如今,当咱们调用bigBoat.boatInfo()并输入函数时,咱们看到它不等于boat, size属性如今是big。为何会这样?这个值在boatInfo()中是如何变化的?

您必须意识到的第一件事是,任何函数中的这个值都不是静态的,它老是在每次调用函数时肯定的,可是在函数实际执行以前,它是代码。函数内部的值其实是由父做用域提供的,在父做用域中调用函数,更重要的是,函数语法是如何编写的。

每当调用一个函数时,咱们必须查看方括号/圆括号“()”的左边。若是在括号的左边咱们能够看到一个引用,那么传递给函数调用的“this”的值就是该对象所属的值,不然它就是全局对象。让咱们来看一些例子:

function bar() {
    alert(this);
}
bar(); // global - 由于方法bar()在调用时属于全局对象

var foo = {
    baz: function() {
        alert(this);
    }
}
foo.baz(); // foo - 由于方法baz()在调用时属于对象foo

若是到目前为止一切都很清楚,那么上面的代码显然是有意义的。经过用两种不一样的方式编写call / invoke语法,咱们能够在同一个函数中更改“this”的值,从而使事情变得更加复杂:

var foo = {
    baz: function() {
        alert(this);
    }
}
foo.baz(); // foo - 由于baz在调用时属于foo对象

var anotherBaz = foo.baz;
anotherBaz(); // global - 由于方法anotherBaz()在调用时属于全局对象,而不是foo

在这里,咱们看到baz()中的“this”值每次都是不一样的,由于它的语法调用有两种不一样的方式。如今,让咱们看看“this”在深度嵌套对象中的值:

var anum = 0;

var foo = {
    anum: 10,
    baz: {
        anum: 20,
        bar: function() {
            console.log(this.anum);
        }
    }
}
foo.baz.bar(); // 20 - 由于()的左边是bar,它在调用时属于baz对象

var hello = foo.baz.bar;
hello(); // 0 - 由于()的左边是hello,它在调用时属于全局对象

另外一个常常被问到的问题是如何在事件处理程序中肯定关键字“this”?答案是,事件处理程序中的“this”老是指向它所触发的元素。咱们来看一个例子:

<div id="test">I am an element with id #test</div>

function doAlert() { 
    alert(this.innerHTML); 
} 

doAlert(); // undefined 

var myElem = document.getElementById('test'); 
myElem.onclick = doAlert; 

alert(myElem.onclick === doAlert); // true 
myElem.onclick(); // I am an element

这里咱们能够看到,当第一次调用doAlert()时,它会发出未定义的警报,由于doAlert()属于全局对象。而后咱们写myElem。onclick = doAlert,它将函数doAlert()复制到myElem的onclick()事件。这基本上意味着不管什么时候触发onclick(),它都是myElem的一个方法,这意味着“This”的值就是myElem对象。

关于这个主题,我想指出的最后一点是,“this”的值也可使用call()和apply()手动设置,覆盖了咱们今天讨论的内容。一样有趣的是,当在函数构造函数中调用“this”时,“this”引用构造函数中全部实例中新建立的对象。缘由是函数构造函数是用“new”关键字调用的,它建立了一个新对象,其中构造函数中的“this”老是引用刚刚建立的新对象。

总结

但愿今天的博客文章已经澄清了对“this”这个关键字的任何误解,你能够一直知道“this”的正确值。咱们如今知道,“this”的值历来不是静态的,它的值取决于函数是如何调用的。

原文:http://davidshariff.com/blog/...

欢迎关注小程序,感谢您的支持!

clipboard.png

相关文章
相关标签/搜索