您好,登錄后才能下訂單哦!
今天小編給大家分享一下JavaScript函數執行上下文的this怎么調用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
關于 this,我們得先從執行上下文說起。我們知道:執行上下文中包含了變量環境、詞法環境、外部環境,當然也包括 this,具體你可以參考下圖:
從圖中可以看出,this 是和執行上下文綁定的,也就是說每個執行上下文中都有一個 this。執行上下文主要分為三種——全局執行上下文、函數執行上下文和 eval 執行上下文,所以對應的 this 也只有這三種——全局執行上下文中的 this、函數中的 this 和 eval 中的 this。
不過由于 eval 我們使用的不多,所以本文我們對此就不做介紹了,如果你感興趣的話,可以自行搜索和學習相關知識。
那么接下來我們就重點講解下全局執行上下文中的 this和函數執行上下文中的 this。
首先我們來看看全局執行上下文中的 this 是什么。
你可以在控制臺中輸入console.log(this)
來打印出來全局執行上下文中的 this,最終輸出的是 window 對象。所以你可以得出這樣一個結論:全局執行上下文中的 this 是指向 window 對象的。這也是 this 和作用域鏈的唯一交點,作用域鏈的最底端包含了 window 對象,全局執行上下文中的 this 也是指向 window 對象。
現在你已經知道全局對象中的 this 是指向 window 對象了,那么接下來,我們就來重點分析函數執行上下文中的 this。還是先看下面這段代碼:
function foo() { console.log(this); } foo();
我們在 foo 函數內部打印出來 this 值,執行這段代碼,打印出來的也是 window 對象,這說明在默認情況下調用一個函數,其執行上下文中的 this 也是指向 window 對象的。估計你會好奇,那能不能設置執行上下文中的 this 來指向其他對象呢?答案是肯定的。通常情況下,有下面三種方式來設置函數執行上下文中的 this 值。
你可以通過函數的call方法來設置函數執行上下文的 this 指向,比如下面這段代碼,我們就并沒有直接調用 foo 函數,而是調用了 foo 的 call 方法,并將 bar 對象作為 call 方法的參數。
let bar = { myName: " name1 ", test1: 1, }; function foo() { this.myName = " name2 "; } foo.call(bar); console.log(bar); console.log(myName);
執行這段代碼,然后觀察輸出結果,你就能發現 foo 函數內部的 this 已經指向了 bar 對象,因為通過打印 bar 對象,可以看出 bar 的 myName 屬性已經由“name1”變為“name2”了,同時在全局執行上下文中打印 myName,JavaScript 引擎提示該變量未定義。
其實除了 call 方法,你還可以使用bind和apply方法來設置函數執行上下文中的 this,僅僅是語法稍有不同。
要改變函數執行上下文中的 this 指向,除了通過函數的 call 方法來實現外,還可以通過對象調用的方式,比如下面這段代碼:
var myObj = { name: " name ", showThis: function () { console.log(this); }, }; myObj.showThis();
在這段代碼中,我們定義了一個 myObj 對象,該對象是由一個 name 屬性和一個 showThis 方法組成的,然后再通過 myObj 對象來調用 showThis 方法。執行這段代碼,你可以看到,最終輸出的 this 值是指向 myObj 的。
所以,你可以得出這樣的結論:使用對象來調用其內部的一個方法,該方法的 this 是指向對象本身的。
其實,你也可以認為 JavaScript 引擎在執行myObject.showThis()
時,將其轉化為了:
myObj.showThis.call(myObj)
接下來我們稍微改變下調用方式,把 showThis 賦給一個全局對象,然后再調用該對象,代碼如下所示:
var myObj = { name: " time ", showThis: function () { this.name = " bang "; console.log(this); }, }; var foo = myObj.showThis; foo();
執行這段代碼,你會發現 this 又指向了全局 window 對象。
所以通過以上兩個例子的對比,你可以得出下面這樣兩個結論:
在全局環境中調用一個函數,函數內部的 this 指向的是全局變量 window。
通過一個對象來調用其內部的一個方法,該方法的執行上下文中的 this 指向對象本身。
你可以像這樣設置構造函數中的 this,如下面的示例代碼:
function CreateObj() { this.name = " time "; } var myObj = new CreateObj();
在這段代碼中,我們使用 new 創建了對象 myObj,那你知道此時的構造函數 CreateObj 中的 this 到底指向了誰嗎?
其實,當執行 new CreateObj() 的時候,JavaScript 引擎做了如下四件事:
首先創建了一個空對象 tempObj;
接著調用 CreateObj.call 方法,并將 tempObj 作為 call 方法的參數,這樣當 CreateObj 的執行上下文創建時,它的 this 就指向了 tempObj 對象;
然后執行 CreateObj 函數,此時的 CreateObj 函數執行上下文中的 this 指向了 tempObj 對象;
最后返回 tempObj 對象。
這樣,我們就通過 new 關鍵字構建好了一個新對象,并且構造函數中的 this 其實就是新對象本身。
就我個人而言,this 并不是一個很好的設計,因為它的很多使用方法都沖擊人的直覺,在使用過程中存在著非常多的坑。下面咱們就來一起看看那些 this 設計缺陷。
我認為這是一個嚴重的設計錯誤,并影響了很多開發者。
至于如何解決?你可以在函數中聲明一個變量 self 用來保存 this。當然也可以使用 ES6 中的箭頭函數來解決這個問題。
上面我們已經介紹過了,在默認情況下調用一個函數,其執行上下文中的 this 是默認指向全局對象 window 的。
不過這個設計也是一種缺陷,因為在實際工作中,我們并不希望函數執行上下文中的 this 默認指向全局對象,因為這樣會打破數據的邊界,造成一些誤操作。如果要讓函數執行上下文中的 this 指向某個對象,最好的方式是通過 call 方法來顯示調用。
這個問題可以通過設置 JavaScript 的“嚴格模式”來解決。在嚴格模式下,默認執行一個函數,其函數的執行上下文中的 this 值是 undefined,這就解決上面的問題了。
以上就是“JavaScript函數執行上下文的this怎么調用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。