MUKI AI Summary
閱讀《前端工程進階大師指南》,了解 JavaScript 中的 this 指向。函式內的 this 在嚴格模式下指向 undefined,非嚴格模式下指向全域物件。用 new 呼叫建構函式,this 指向新物件。用 call、apply、bind 呼叫函式,this 指向指定物件。上下文物件呼叫函式,this 指向該物件。箭頭函式內的 this 由外層作用域決定,無法改變。箭頭函式的 this 優先順序最高,其次是顯示綁定 (call、apply)。...
書籍參考
最近趁閒暇之餘會閱讀 JS 專業書籍,目前在看的是由侯策所寫的前端工程進階大師指南,有興趣的朋友可以點擊以下書籍資訊,連至博客來網站。
頂級網站技術長高度:前端工程進階大師指南
書名:頂級網站技術長高度:前端工程進階大師指南,語言:繁體中文,ISBN:9789865501877,頁數:656,出版社:深智數位,作者:侯策,出版日期:2021/04/19,類別:電腦資訊
https://www.books.com.tw/products/0010888346
這邊會針對看完的章節,做一些簡單的分享與個人的理解筆記,有興趣的朋友可以參考看看,如有任何錯誤也請指正囉!
this 的指向
有一種廣為流傳的說法是:誰呼叫 this
,this
就指向誰。
而書中有作者統整的幾個 this
指向規律:
- 於函式本體呼叫
function
時,在嚴格模式下,函式內的this
會指向undefined
;非嚴格模式下,this
會指向全域物件 (ex.window
/global
) 。 - 用
new
方法呼叫建構函式時,函式內的this
會指向新建立的物件。 - 透過
call
/apply
/bind
等方法呼叫函式時,函式內的 this 會指向指定參數的物件。 - 透過上下文物件呼叫函式時,函式內的
this
會指向該物件。 - 在箭頭函式中,
this
的指向,是由外層 (ex. 函式或全域) 作用域來決定的。
以下針對該五種狀況,做更深入的筆記與範例介紹。
於函式本體呼叫 function
標題這句話轉譯成程式碼,大致如下,就是很單純的呼叫 function
。
function fn1() { console.log(this) } function fn2() { 'use strict' console.log(this) } fn1() // window fn2() // undefined
兩種的差別,在於有無使用嚴格模式 ('use strict'
)。
什麼是嚴格模式
我個人覺得嚴格模式有點像 ES Lint 或 TypeScript,就是讓你用更嚴謹的寫法去寫 JavaScript。如果要使用嚴格模式,只要將 'use strict'
加上程式碼前方即可,也可以只加在 function
裡,例如上述範例的第 6 行,這樣就只對 fn2()
有作用。
不能用在嚴格模式的寫法
關於在嚴格模式中,哪些寫法不能寫?我覺得 itsems 的 Javascript 的嚴格模式 (Strict Mode):不讓你錯 已經寫得很清楚了,以下擷取標題讓大家參考,文章內也有更詳細的範例程式碼,有興趣的朋友可以點擊閱讀。
直接定義未宣告變數
使用 delete 刪除變數或函式
重複變數
使用 8 進位值
使用 with
eval、arguments 不能當作變數名稱
this 禁止指向全域
Javascript 的嚴格模式 (Strict Mode):不讓你錯
而最後一點:this
禁止指向全域,就是我們要講的主題 XD,因此在嚴格模式下,this
會改指向 undefined
。
用 new 方法呼叫建構函式
當我們用 new
呼叫建構函式時,需要用 this
來創造新物件。這時候的 this
,就會被綁在新物件上:
function Human(age) { // 用 this 創造新物件 this.age = age } const muki = new Human(20) console.log(muki.age) // 20
用 new
呼叫建構函式,實際上做了什麼事呢?以下提供簡略流程給大家參考:
- 建立一個新的物件
- 將建構函式的
this
指向剛建立的新物件 - 為這個物件增加屬性、方法 ... 等
- 回傳新的物件
透過 call / apply / bind 等方法呼叫函式
利用 call()
, apply()
以及 bind()
可以改變 this
的指向,以下舉個很簡單的例子 (大家應該都看到爛掉了 XD)
const obj = { name: 'muki' } function data() { console.log(this.name) } data.bind(obj)()
透過 bind()
,data
設定的 this
就會變成是 bind()
裡的物件。而 call()
以及 apply()
也是類似的概念,這邊就不再贅述了。
透過上下文物件呼叫函式
以上下文物件來判斷的話,基本上就是簡單的「誰呼叫 this
,this
就指向誰」的概念。
const person = { name: 'Lucas', brother: { name: 'Mike', fn: function() { return this.name } } } console.log(person.brother.fn())
由上述例子來看,最後呼叫 this
的是 person.brother
物件,因此 this.name
會是 Mike。
箭頭函式中的 this
在箭頭函式裡的 this
在 function
建立時,就已經由外層的作用域來決定 this
指向誰,而且不管用前面提到的 'use strict'
,call
/ apply
/ bind
... 等,都沒辦法改變 this
的指向。
const button = document.querySelector('button') const arrowFn = () => { // 建立 function 時 this 指 Window console.log(this.constructor.name) // 執行 function 時 this 指 Window } const fn = function () { // 建立 function 時 this 指 Window console.log(this.constructor.name) // 執行 function 時 this 指 HTMLButtonElement } button.addEventListener('click', arrowFn()) button.addEventListener('click', fn())
使用傳統 function
寫法,在 button
執行 click
事件後,this 就會指向呼叫他的 button
上。而使用箭頭函式,不管是誰呼叫,this
永遠是由外層的作用域來決定,不會被改變。
this 的優先順序
箭頭函式最高
包在箭頭函式裡的 this
,無法被各種寫法改變指向,所以他的優先順序最高。
顯示綁定 (call / apply) 比隱式綁定高
接著來比較「以上下文物件呼叫」和「用 call
/ apply
」指定 this
,看哪一個為優先:
function foo(a) { console.log(this.a) } const obj1 = { a: 1, foo: foo } const obj2 = { a: 2, foo: foo } obj1.foo.call(obj2) // output: 2 ojb2.foo.call(obj1) // output: 1
如果沒有用 call
去指定 this
,那 obj1.foo()
根據上下文判定,會顯示 1。但我們用了 call()
將 this
指向 obj2
,所以會顯示 2。
因此可以知道,call
/ apply
的優先順序會比較高。
原本只是想了解「嚴格模式」,卻一路回去看 this 的指向,然後將書上的介紹整理成讀書心得 xD。讓我想起多年前閱讀 深入淺出 JavaScript 時,也做過類似的讀書心得 XDDD。
希望可以藉由撰寫部落格,把 前端工程進階大師指南 閱讀理解完全,目前看來是本好書,我要慢慢的消化吸收,加油加油 💪!
不知道能不能請您解惑?
文中多處提到:用
new
方法呼叫建構函式時,函式內的this
會指向新建立的物件。但是以下程式的第二個 this,指向的卻是 cat 物件,而非新物件 newCat。是不是我有哪裡理解錯了呢?
<script>
(function myFunc(){
console.log(this)
})();
var cat= function (){
console.log(this)
};
var newCat= new cat()
</script>
我這邊看來,你定義了一個 function cat,但是 function 裡面沒有修改對象的屬性,所以輸出的時候就是空的對象,這樣看起來就很像是指到 cat,而非 newCat
假設在 function 裡面,增加一個對象的屬性,例如:
var cat = function () {
console.log(this);
this.color = 'black';
return this;
};
var newCat = new cat();
console.log(newCat); // 會輸出 {color: "black"}
這樣印出 newCat 時,可以看到 this 指到的是新的物件。
以上是我的理解,不知道對你有沒有幫助 QQ