摘要:原文許多人被中的關(guān)鍵字給困擾住了,我想混亂的根源來自人們理所當(dāng)然地認(rèn)為中的應(yīng)該像中的或中的一樣工作。盡管有點(diǎn)難理解,但它的原理并不神秘。在瀏覽器中,全局對象是對象。運(yùn)算符創(chuàng)建一個新對象并且設(shè)置函數(shù)中的指向調(diào)用函數(shù)的新對象。
原文:Understanding the "this" keyword in JavaScript
許多人被JavaScript中的this關(guān)鍵字給困擾住了,我想混亂的根源來自人們理所當(dāng)然地認(rèn)為JavaScript中的this應(yīng)該像Java中的this或Python中的self一樣工作。盡管JavaScript的this有時有類似的效果,但它跟Java或其他語言中的this是完全不同的。盡管有點(diǎn)難理解,但它的原理并不神秘。事實(shí)上,this遵循一些簡單的小規(guī)則,這篇文章就對這些規(guī)則作出了解釋。
但首先,我想給出一些專業(yè)術(shù)語和一些JavaScript運(yùn)行時環(huán)境的相關(guān)信息,希望能幫助你構(gòu)建一個心智模型來更好的理解this。
執(zhí)行上下文每一行JavaScript代碼都運(yùn)行在一個“執(zhí)行上下文”中。JavaScript運(yùn)行時環(huán)境用一個棧維持著這些上下文,棧頂?shù)囊粋€就是當(dāng)前正在運(yùn)行的執(zhí)行上下文。
有三類可執(zhí)行代碼:全局代碼(global code),函數(shù)代碼(function code),eval代碼(eval code)。大概的說,全局代碼是應(yīng)用程序最頂層的代碼,不被包含在任何方法中,函數(shù)代碼是在函數(shù)(function)體中的代碼,eval代碼是被eval解釋的全局代碼。
this對象每次控制進(jìn)入一個新的執(zhí)行上下文時會被重新確定指向,直到控制切換到一個不同的上下文。this的值取決于兩件事:被執(zhí)行的代碼的類型(global,function,eval)和調(diào)用代碼的對象。
全局對象所有的JavaScript運(yùn)行時都有一個唯一的全局對象。他的屬性包括內(nèi)置的對象如Math和String,以及其他由主環(huán)境變量定義的屬性。
在瀏覽器中,全局對象是window對象。在Node.js中,它就叫作“global object”。(我假定你將在瀏覽器中運(yùn)行代碼,然而,我所說的一切也同樣適用于Node.js。)
確定this的值第一條規(guī)則很簡單:this指向全局對象在所有全局代碼中。由于所有的程序都是由執(zhí)行全局代碼開始的,并且this在給定的執(zhí)行上下文中會被修正,所以,默認(rèn)的this指全局對象。
當(dāng)控制進(jìn)入一個新的執(zhí)行上下文時發(fā)生了什么呢?只有三種this的值發(fā)生改變的情況:方法調(diào)用,new一個函數(shù)對象,函數(shù)被call和apply調(diào)用。我將逐一解釋。
方法調(diào)用當(dāng)我們通過點(diǎn)(例obj.foo())或者方括號(例obj["foo"])把一個方法作為一個對象的屬性來調(diào)用時,this將指向方法體的父對象:
var counter = { val: 0, increment: function () { this.val += 1; } }; counter.increment(); console.log(counter.val); // 1 counter["increment"](); console.log(counter.val); // 2
這是第二條規(guī)則:函數(shù)被當(dāng)作父對象的屬性來調(diào)用時,在函數(shù)代碼中的this指向函數(shù)的父對象。
注意,如果我們直接調(diào)用相同的方法,即,不作為父對象的屬性,this將不會指向counter對象:
var inc = counter.increment; inc(); console.log(counter.val); // 2 console.log(val); // NaN
當(dāng)inc被調(diào)用時,這里的this不會改變,所以它還是指向全局對象。
當(dāng)inc執(zhí)行
this.val += 1;
它等效于執(zhí)行:
window.val += 1;
window.val是undefined,且undefined加1得到NaN。
new 運(yùn)算符任何JavaScript函數(shù)都可以通過new運(yùn)算符當(dāng)成構(gòu)造函數(shù)使用。new運(yùn)算符創(chuàng)建一個新對象并且設(shè)置函數(shù)中的this指向調(diào)用函數(shù)的新對象。舉個栗子:
function F (v) { this.val = v; } var f = new F("Woohoo!"); console.log(f.val); // Woohoo! console.log(val); // ReferenceError
這就是我們的第三條規(guī)則:在用new運(yùn)算符調(diào)用的函數(shù)代碼中的this指向新創(chuàng)建的對象。
注意F沒有任何特殊。如果不通過new調(diào)用,this將指向全局對象:
var f = F("Oops!"); console.log(f.val); // undefined console.log(val); // Oops!
在這個例子中,F("Oops!")是一個通常調(diào)用,this沒有指向新的對象,因?yàn)闆]有用new創(chuàng)建新的對象,this繼續(xù)指向全局對象。
Call & Apply所有JavaScript函數(shù)都有兩個方法,call和apply,讓你能夠調(diào)用函數(shù)并且清楚的設(shè)置this指向的對象。apply函數(shù)有兩個參數(shù):一個是this指向的對象,一個(可選)傳進(jìn)函數(shù)的參數(shù)的數(shù)組:
var add = function (x, y) { this.val = x + y; }, obj = { val: 0 }; add.apply(obj, [2, 8]); console.log(obj.val); // 10
call方法和apply方法是完全一樣的,只不過要逐個的傳遞參數(shù),而不是用一個數(shù)組:
add.call(obj, 2, 8); console.log(obj.val); // 10
這是第四條規(guī)則:當(dāng)使用call或apply調(diào)用函數(shù)時,函數(shù)代碼中的this被設(shè)置為call或apply中的第一個參數(shù)。
總結(jié)默認(rèn)的,this指向全局對象
當(dāng)一個函數(shù)被作為一個父對象的屬性調(diào)用時,函數(shù)中的this指向父對象
當(dāng)一個函數(shù)被new運(yùn)算符調(diào)用時,函數(shù)中的this指向新創(chuàng)建的對象
當(dāng)使用call或apply調(diào)用函數(shù)時,函數(shù)代碼中的this被設(shè)置為call或apply中的第一個參數(shù)。如果第一個參數(shù)是null或不是個對象,this指向全局對象。
如果你理解并接受了上面的4條規(guī)則,你就能明白this指的是什么了。
補(bǔ)充:eval打破上面所有規(guī)則Remember when I said that code evaluated inside eval is its own type of executable code? Well, that’s true, and it means that the rules for determining what this refers to inside of eval code are a little more complex.
As a first pass, you might think that this directly inside eval refers to the same object as it does in eval’s caller’s context. For example:
var obj = { val: 0, func: function() { eval("console.log(this.val)"); } }; obj.func(); // 0
That works likely as you expect it to. However, there are many cases with eval where this will probably not work as you expect:
eval.call({val: 0}, "console.log(this.val)"); // depends on browser
The output of the above code depends on your browser. If your JavaScript runtime implements ECMAScript 5, this will refer to the global object and the above should print undefined, because it’s an “indirect” call of eval. That’s what the latest versions of Chrome and Firefox do. Safari 5.1 actually throws an error (“The ‘this’ value passed to eval must be the global object from which eval originated”), which is kosher according to ECMAScript 3.
If you want know how this works with eval, you should read Juriy Zaytsev’s excellent, “Global eval. What are the options?” You’ll learn more about eval, execution contexts, and direct vs. indirect calls than you probably ever wanted to know.
In general, you should just avoid using eval, in which case the simple rules about this given previously will always hold true.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/85719.html
摘要:在中,當(dāng)使用關(guān)鍵字調(diào)用函數(shù)構(gòu)造函數(shù)時,函數(shù)構(gòu)造函數(shù)中也有這個概念,但是它不是惟一的規(guī)則,而且常??梢砸脕碜圆煌瑘?zhí)行上下文的不同對象。因此,我們使用調(diào)用函數(shù),可以看到這是對象,并且的屬性是正常的。 一直以來,javascript里邊的this都是一個很難理解的東西,之前看的最多的就是阮一峰老師關(guān)于this的理解: http://www.ruanyifeng.com/blo... htt...
摘要:除此之外,還有一種情況也會修改,在一些庫中傳入回調(diào)函數(shù),可能會強(qiáng)制改變的綁定,例如在中本例中的就是被強(qiáng)制改變綁定到了觸發(fā)事件的元素上。它們的第一個參數(shù)是一個對象,它們會把這個對象綁定到,接著在調(diào)用函數(shù)時指定這個。 理解JavaScript中的this關(guān)鍵詞 this關(guān)鍵詞是JavaScript語言中一個很重要,同時也是一個非常復(fù)雜的機(jī)制,它同時也是一個很特殊的關(guān)鍵詞,它一般會被自動定義...
摘要:理解了這句話,我們就可以來看閉包了閉包前面說過,函數(shù)可以訪問函數(shù)作用域鏈中的變量,但如果我們想在函數(shù)外訪問函數(shù)內(nèi)卻不行了。 不管是閉包還是this關(guān)鍵字,都是困擾JS初學(xué)者的比較難懂的東西,如果你對它們的認(rèn)識還不足夠清晰,那么現(xiàn)在就一起把它們掌握掉。還是那句話,我們從最基本的開始,建立起一個非常清晰的知識結(jié)構(gòu),好了,開始吧 ? 閉包 當(dāng)然我們今天說的是javascript里的閉包。要學(xué)...
摘要:然而,異步函數(shù)不會立即被推入調(diào)用堆棧,而是會被推入任務(wù)隊(duì)列,并在調(diào)用堆棧為空后執(zhí)行。將事件從任務(wù)隊(duì)列傳輸?shù)秸{(diào)用堆棧稱為事件循環(huán)。我們調(diào)用接受和或返回另一個函數(shù)稱為高階函數(shù)的函數(shù)。 為了保證可讀性,本文采用意譯而非直譯 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 1.如何理解 JS 中的this關(guān)鍵字? JS 初學(xué)者總是對 this 關(guān)鍵字感到困惑,因?yàn)榕c其他現(xiàn)...
摘要:原文鏈接參考深入理解原型和閉包完結(jié)王福朋博客園中的作用域詳解博客園 前言 王福朋老師的 JavaScript原型和閉包系列 文章看了不下三遍了,最為一個初學(xué)者,每次看的時候都會有一種 大徹大悟 的感覺,而看完之后卻總是一臉懵逼。原型與閉包 可以說是 JavaScirpt 中理解起來最難的部分了,當(dāng)然,我也只是了解到了一些皮毛,對于 JavaScript OOP 更是缺乏經(jīng)驗(yàn)。這里我想總...
閱讀 1936·2021-11-24 09:39
閱讀 3518·2021-09-28 09:36
閱讀 3290·2021-09-06 15:10
閱讀 3444·2019-08-30 15:44
閱讀 1159·2019-08-30 15:43
閱讀 1802·2019-08-30 14:20
閱讀 2717·2019-08-30 12:51
閱讀 2035·2019-08-30 11:04