This:從執行上下文的角度來了解這個。
這在全局執行上下文中
讓我們首先看看這在全局執行上下文中是什麼。
可以在控制台輸入console.log(this)在全局執行上下文中列印出這個,最後輸出的是window對象。是以你可以得出結論,這在全局執行上下文中指向視窗對象。這也是This和scope鍊的唯一交集。作用域鍊的底部包含視窗對象,在全局執行上下文中也指向視窗對象。
這是在函數執行的上下文中
既然您知道全局對象中的這個對象指向視窗對象,那麼讓我們在函數執行的上下文中關注這個對象。或者先看看下面的代碼:
函數foo() {
console . log(this);
}
foo();
複制代碼
我們在foo函數中列印出這個值,當我們執行這段代碼時,我們也列印出視窗對象,這意味着當一個函數被預設調用時,它的執行上下文中也指向視窗對象。你可能很好奇,但是你能在執行上下文中設定它指向其他對象嗎?答案是肯定的。通常,在函數執行的上下文中有三種方法來設定該值。
1.由函數的調用方法設定。
可以通過函數的call方法設定函數執行上下文的這個點。比如下面這段代碼,我們沒有直接調用foo函數,而是調用了foo的call方法,并把bar對象作為call方法的參數。
讓bar = {
我的名字:“名字1”,
測試1: 1,
};
函數foo() {
this.myName = " name2
}
foo.call(酒吧);
console . log(bar);
console.log(我的名字);
複制代碼
執行這段代碼,然後觀察輸出結果,可以發現foo函數内部這個已經指向了bar對象,因為通過列印bar對象,可以看到bar的myName屬性從“name1”變成了“name2”,同時在全局執行上下文中列印myName,JavaScript引擎提示這個變量是未定義的。
實際上,除了call方法之外,您還可以使用bind和apply方法在函數執行的上下文中設定它,但是文法略有不同。
2.通過對象調用方法設定。
要在函數的執行上下文中更改這一點,除了函數的調用方法之外,還可以由對象調用,如下面的代碼:
var myObj = {
姓名:“姓名”,
showThis: function () {
console . log(this);
},
};
myobj . show this();
複制代碼
在這段代碼中,我們定義了一個由name屬性和showThis方法組成的myObj對象,然後通過myObj對象調用showThis方法。執行這段代碼,可以看到這個值的最終輸出指向myObj。
是以,你可以得出結論,用一個對象調用它内部的一個方法,方法的this指向對象本身。
其實你也可以認為,當JavaScript引擎執行myObject.showThis()時,它被轉化為:
myObj.showThis.call(myObj)
接下來,讓我們稍微改變一下調用方法,将showThis賦給一個全局對象,然後調用該對象。代碼如下:
var myObj = {
名稱:“時間”,
showThis: function () {
this.name = " bang
console . log(this);
},
};
var foo = myObj.showThis
foo();
複制代碼
執行這段代碼,你會發現這又指向了全局視窗對象。
是以通過比較以上兩個例子,可以得出以下兩個結論:
在全局環境中調用一個函數,這個函數内部指向全局變量視窗。
在對象内部調用一個方法,這個方法的執行上下文中的this指向對象本身。
3.通過在構造函數中設定
您可以像下面這樣在構造函數中設定它,如下面的示例代碼所示:
函數CreateObj() {
this.name = " time
}
var myObj = new create obj();
複制代碼
在這段代碼中,我們使用new來建立對象myObj。你知道構造函數CreateObj中的這個指向誰嗎?
實際上,當執行new CreateObj()時,JavaScript引擎會做以下四件事:
首先,一個空對象tempObj已建立;
然後調用CreateObj.call方法,使用tempObj作為調用方法的參數,這樣在建立CreateObj的執行上下文時,其this指向tempObj對象;
然後執行CreateObj函數,此時CreateObj函數的執行上下文中this指向tempObj對象;
最後,傳回tempObj對象。
這樣,我們通過new關鍵字建構了一個新對象,而這個在構造函數中實際上就是新對象本身。
設計缺陷及其解決方案
個人認為這不是一個好的設計,因為它的很多使用方法沖擊了人的直覺,在使用過程中也有很多漏洞。讓我們來看看這些設計缺陷。
1.嵌套函數中的這一點不會從外部函數中繼承。
我認為這是一個嚴重的設計錯誤,也影響了很多開發者。
至于怎麼解決?你可以在函數中聲明一個變量self來儲存它。當然,你也可以使用ES6中的箭頭功能來解決這個問題。
2.這在普通函數中預設指向全局對象視窗。
如上所述,預設情況下調用一個函數,預設情況下,這個函數在其執行上下文中指向全局對象視窗。
但這種設計也是一個缺陷,因為在實際操作中,我們并不希望函數執行的上下文中這個預設指向全局對象,因為這樣會打破資料邊界,造成一些誤操作。如果希望在函數執行的上下文中指向一個對象,最好的方法是通過call方法顯示調用。
這個問題可以通過設定JavaScript的“嚴格模式”來解決。在嚴格模式下,預設執行一個函數,在其函數的執行上下文中this的值是未定義的,解決了上述問題。
摘要
審查以下内容:
首先,在使用這個的時候,為了避免坑,你要記住以下三點:
當一個函數作為一個對象的方法被調用時,函數中的這個就是對象;
正常調用函數時,在嚴格模式下,this的值是未定義的,在非嚴格模式下,this指向全局對象視窗;;
嵌套函數中的This不繼承外部函數的這個值。