iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
自我挑戰組

JavaScript 奇奇怪怪的核心觀念系列 第 17

(Day17) this 介紹下 - 綁定 this 的 call & apply & bind 與嚴格模式

前言

上篇大致講解了 this 在不同狀況的指向,這篇會來講講使用 call/apply/bind 來綁定 this, 以及在嚴格模式下 this 指向會有所不同。

綁定 this 的 call/apply/bind

當我們遇上某些需求,要求 XX 函式中的 this 是某個特定物件,這時便會使用 call()apply()bind() 來調整特性函式中的 this

這三個方法和 filter()forEach() 一樣是藉由原型提供的,因此這三個方法,不需要任何設定便可使用,這邊先來看看範例

var name = 'Ryder'
function showName() {
  console.log(this.name) 
}
showName()

這是上一篇文章中 this 指向 window 的一個範例,這邊試者使用 call() 方法,並且將一個新增的物件當作參數傳入,如:

var name = 'Ryder'
var obj = {
	name : 'Jack'
}
function showName(item1,item2,item3) {
  console.log(this.name,item1,item2,item3) // Jack, test, {}, [0,1,2]
}
showName.call(obj,'test', {}, [0,1,2])

結果 showName 中的 this 會變成指向 obj 要注意的是使用 showName.call(obj) 他會立刻就回傳,這是因為 call() 這個方法是使用後,會立刻執行函式,並且修正函式中的 this ,順帶一題在 call() 第一個參數是用來綁定函式中 this 的,第一個參數後面的參數,則都是傳遞給原本函示的參數。

apply()call() 差異則是剛剛提到的 第一個參數後面的參數部分, 其他地方完全一致,call() 第一個參數後面的參數,是接受任何型別的參數 ,而 apply() 則只能使用第二個參數,並且只能接受陣列寫法的參數,如果是陣列以外的都會跳錯。

var name = 'Ryder'
var obj = {
	name : 'Jack'
}
function showName(item1,item2,item3){
  console.log(this.name,item1,item2,item3)
}
showName.apply(obj,['test',{}, [0,1,2] ]) // Jack, test, {}, [0,1,2] 
showName.apply(obj,'test', {}, [0,1,2]) // 跳錯

bind() 算是比較常用的,和 call()apply() 不同,使用後函示並不會立刻執行,而是會回傳要替換 this 的函式,因此我們會需要再使用 () 呼叫替換後的函式,而參數部分則和 call() 接受任何形式的參數。

var name = 'Ryder'
var obj = {
	name : 'Jack'
}
function showName(item1,item2,item3){
  console.log(this.name,item1,item2,item3)
}
var test = showName.bind(obj) 
test('test', {}, [0,1,2])

關於 call()apply() 、 bind() 還有一點要提的是,使用第一個參數綁定 this 時,若如果我們傳入的是純值,那麼被替換的 tihs 會是以建構式的方式建立。

function Fn1(){
   console.log(this) //String {'test'}
}
Fn1.bind('test')()

而傳入 undefined 他則會替換成 window

function Fn1(){
   console.log(this) // Window
}
Fn1.call(undefined)

關於這一點 MDN 也有解釋:

注意,它可能是一個無法在函數內看到的值:若這個函數是在非嚴苛模式( non-strict mode ), null 、undefined 將會被置換成全域變數,而原生型態的值將會被封裝

嚴格模式

由於 JavaScript 這個語言特性,算是相對寬鬆,因此 ES5 新增 嚴格模式,用來規範 JavaScript 寫法,並對程式碼做一些限制。

若要使用嚴格模式會需要再該執行環境添加 'use strict' 的字串,如果我們直接在全域使用 'use strict' 基本上就是全部的程式碼都會變為嚴格模式。

而我們本次介紹的 this 在嚴格模式下,部分的指向也會有所變動,那麼嚴格模式下 this 有甚麼更動?

主要有三點:

  • 簡易呼叫 this 原本指向 window ,嚴格模式下一律都會被轉為 undefined
  • 使用 call()apply()bind()this 值做綁定時,若綁定的是純值, this 的值會是建構式,嚴格模式下則會是純值本身。
  • 同上透過 call()apply()bind()this 值做綁定時,綁定的是 undefinedNullthis 會是 window,嚴格模式下則會是傳入的 undefinedNull

簡易呼叫的範例:

var name = 'Ryder'
var array = [1,2,3]
function Fn() {
	'use strict'
  console.log(this) // undefined 
}
Fn()

array.forEach(function(){
	'use strict'
	console.log(this) //undefined *3
})

this 綁定 undefined 、與純值的範例

function Fn1(){
	'use strict'
   console.log(this) // undefined
}
Fn1.call(undefined)

function Fn2(){
	'use strict'
   console.log(this) // 'test'
}
Fn2.call('test')

參考文獻


上一篇
(Day-16) this 介紹上 - this 的指向
下一篇
(Day18) 原型特性與繼承
系列文
JavaScript 奇奇怪怪的核心觀念30

尚未有邦友留言

立即登入留言