天天看點

This:從執行上下文的角度來了解這個

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不繼承外部函數的這個值。