JavaScript this
this 是什麼?
- this 用來 ‘傳遞’ 一個 object 的引用
- function 呼叫方法會影響 this
- 在同個範圍(global,function)裡面傳遞不同的東西(物件,變數)
this 判定方式
- 判斷函數被調用時 this 指向誰,立馬看 ( ) 左邊的部分
- 如果 ( ) 左邊是一個引用(參照),那麼函數 this 指向的就是這個引用所屬的對象
- 否則 this 指向的就是全局對象(global)
- this 會因執行的環境與上下文 (context) 的不同,而有不同的結果
1 | var foo = { |
context 是什麼?
- 函式在被呼叫執行時,所處的物件環境
‘use strict’
- 在非嚴格模式下,this 的內容就會是global 物件
- 在嚴格模式下,this 的內容就會是 undefined
有什麼方法
- 默認綁定 Global Object (Window 物件)
- 隱式綁定 函數功能(function)
- 顯式綁定 (call、apply、bind)
- 建構式綁定(constructor)
- DOM
方法有什麼效果
默認綁定 Global Object (Window 物件)
- 不加任何的修飾符直接調用函數
- 瀏覽器的執行環境下,global object 指的就是 Window 物件
- NodeJS 的執行環境下,global object 指的就是 Global 物件
1 | console.log(this) // Window |
隱式綁定 函數功能(function)
- 呼叫的物件不同,所以執行的結果也會不同
1 | // 回到上一層 this = widows 在指定到 a,b |
- 物件在指向的時候是 by reference 的方式
- window 錯誤 - 在物件方法內再建立方法(function)時,物件屬性值指向 window 並經由 scop china 找到上一層的物件屬性值 所以 再次設定的物件屬性不會等於正確設定的屬性值
可由 let self = this , let that = this 來設定取代
一般寫法
1 | // f1 function 執行完後離開 execution stack ,所以在執行 f2 function 會指定到 window |
- 嚴格模式 ‘use strict’
1 | // 嚴格模式 不允許使用內層 this |
- 解法
1 | // 解法1.指定變數給 this |
顯式綁定 (call、apply、bind)
- 為什麼要用 顯示綁定?
- callback function 中的 this 往往會改變指向,造成不是我們要的結果
- 明確(強制)指定要執行 function 中的 this 是什麼,就不用透過另一個變數來暫存 this 的方式來獲取
function method
- call
function.call (thisArg, arg1, arg2, ...)
- 提供的 this 值與傳入參數值(arguments)傳進目標函式
- apply
function.apply (thisArg, [argsArray])
- this 值傳入外,另一個傳入參數值使用 array
- call apply 兩者共通
- 重新定義函數的執行環境(this)
- 使用在 context 較常變動的場景,依照呼叫時的需要帶入不同物件作為該 function 的 this
- thisArg 可以指定為 null,this 指向為 window
- 呼叫的當下就立即執行
- call apply 差異
- 傳入參數的形式不同
1 | 貓吃魚,狗吃肉,有一天貓不僅想吃肉,還想吃豬肉牛肉羊肉 |
- 以 DOM 來看 call 和 apply 可以用來重新定義函數的執行環境(this的指向)
1 | function changeStyle(attr, value){ |
- thisArg 可以指定為 null,this 指向為 window
1 | function add(a,b){ |
- Math 中用 apply 把 array 當參數傳入直接求 array 中最大值,不用自己去遍歷求值
1 | let arr = (6,3,2,8,9) |
- bind
function.bind (thisArg[, arg1[, arg2[, ...]]])
- 前者為套用 this 的物件,後者以後都是 function 的參數
- 使用 bind 寫死要綁定的物件,可避免函式呼叫時退回到預設綁定
- 執行 function 前,綁定指定的物件這樣 this 就會是這個物件
- 新函式在呼叫時,建立一個新函式提供的 this 值與一連串的傳入參數值來進行呼叫,不需要參數則不要傳入即可
- 常用在像是 callback function 這種類型,可以先綁定好 this,然後讓 function 在需要時才被呼叫
- 不會立即執行
1 | var obj = { |
- 硬綁定(hard binding)是指使用 bind 寫死要綁定的物件,可避免函式呼叫時退回到預設綁定
1 | /* |
function currying
- 類似預設參數
- 將接受 n 個參數的 function,轉變成 n 個到只接受一個參數的 function 過程
- 簡化參數的處理,基本上是一次處理一個參數,藉以提高程式的彈性和可讀性
1 | // setTimeout function 的 this 指向為 window |
- 實例
1 | // function currying |
建構式綁定(constructor 物件產生時會被呼叫的方法)
- new constructor[([arguments])]
- 這個新建構的物件 this 會指向新建構的物件
1 | let x = 2; |
DOM
- 元素觸發事件,this 就指向那個元素
- DOM 調用 function 就如同物件調用 function,所以此 this 所指向的則是該 DOM
1 | function doAlert() { |
比較優先順序
- 顯式綁定和建構式綁定無法直接比較(會報錯)
- 匹配的優先順序由 高至低排列
- 建構式綁定:this 會指向 new 出來的物件
- 顯示綁定:使用 call、apply、bind,明確指出要綁定給 this 的物件
- 隱式綁定:當函式為物件的方法(method)時,在執行階段 this 就會被綁定至該物件
- 預設綁定:當其他規則都不適用時,沒有使用 bind、call、apply 或不屬於任何物件的 method,就套用預設綁定,在非嚴格下,瀏覽器環境 this 的值就是預設值
全域物件 window
,而在嚴格模式下,this 的值就是undefined
結論
- this 代表的是 function 執行時所屬的物件
- 判斷函數被調用時 this 指向誰,立馬看 ( )左邊的部分
- function 內用嚴格模式下,默認的 this 就是 undefined
- 可由 let self = this , let that = this 來設定變數取代 this
- call、apply、bind 明確(強制)指定要執行 function 中的 this 是什麼,不用設定變數
- new 綁定這個新建構的物件 this 會指向新建構的物件
- DOM 元素觸發事件,this 就指向那個元素
執行方式 | 範例語法 | this等於 |
---|---|---|
Global | this | Global object (eg. window) |
Global Function | foo() | Global object |
Object Function | myObject.foo() | myObject |
Function using call | foo.call(myCall,myArg) | myCall |
Function using apply | foo.apply(myCall,[myArgs]) | myApply |
Constructor Function | var newObj = new foo() | newObj |
Evaluation | eval(thing_to_eval) | 等同eval層級 |
顯式綁定 | bind | call | apply |
---|---|---|---|
適用狀況 | 在執行前先綁定物件做為該 function 的 this,需要時才被呼叫不會立即執行 | 依照呼叫時的需要帶入不同的物件作為該 function 的 this,在呼叫的當下就立即執行 | 與 call 相同 |
傳參數的方式 | 代入指定的物件 func.bind (thisArg[, arg1[, arg2[, ...]]]) |
參數需要一個一個指定 function.call (thisArg, arg1, arg2, ...) |
參數使用陣列傳入 function.apply (thisArg, [argsArray]) |
element.addEventListener 中使用 this & e.target & e.currentTarget 差異
- this 總是會拿到被監聽的對象本身,也就是 element.addEventListener(
) 的 element - e.currentTarget === this
- e.target 則是指事件被觸發時的對象,有可能不是 element 本身
1 | <div class="hero"> |