Photo by Mohammad Rahmani on Unsplash
函式方法
變數 | 說明 |
---|---|
Function.call() | 執行函式,並改變函式中的 this 物件為指定變數,函式參數依序帶入 |
Function.apply() | 執行函式,並改變函式中的 this 物件為指定變數,函式參數為陣列 |
Function.bind() | 建立函式,並改變函式中的 this 物件為指定變數,下次呼叫時會使用改變過後的 this 物件執行 |
綁定 this 方式
call
與apply
皆是直接執行函式,只是參數傳入方式不同bind
會綁定this
並回傳已綁定函式,在之後呼叫執行
function add(a, b) {
return a + b;
}
// call
console.log(add.call(null, 1, 2)); // 3
console.log(add.call(null, 1, 4)); // 5
// apply
console.log(add.apply(null, [1, 2])); // 3
console.log(add.apply(null, [1, 4])); // 5
// bind
let add1 = add.bind(null, 1);
console.log(add1(2)); // 3
console.log(add1(4)); // 5
call
傳入參數第一個是要改變的 this 變數,後面是函式需要用的參數,依序列出
Function.call(要改變的this, 參數1, 參數2...)
apply
傳入參數只有 2 個,函式用的參數用陣列包起來傳入
Function.apply(要改變的this, [參數1, 參數2...])
bind
Function.bind(要改變的this, 參數1, 參數2...)
函式預設值
在傳入參數後方加入 =
即可設定預設值
const SayHi = (name, age = 17) => {
console.log(`My name is "${name}", and my age is "${age}"`);
}
// My name is "Kay", and my age is "19"
SayHi('Kay', 19);
// My name is "Jay", and my age is "17"
SayHi('Jay');
舊的設定預設值方式
const SayHi = (name, age ) => {
age = age || 17;
console.log(`My name is "${name}", and my age is "${age}"`);
}
// My name is "Kay", and my age is "19"
SayHi('Kay', 19);
// My name is "Jay", and my age is "17"
SayHi('Jay');
使用 new 建立 Function 實例
new
會讓 this
指向到新建立的物件實體
function Animal(name) {
this.name = name;
this.walk = () => {
console.log(`[Animal] ${this.name} walking`);
}
}
let myAnimal = new Animal('Kay');
// Animal { name: 'Kay', walk: [Function (anonymous)] }
console.log(myAnimal);
用函式縮寫的方式沒辦法順利 new
物件實例
let Animal = (name) => {
this.name = name;
this.walk = () => {
console.log(`[Animal] ${this.name} walking`);
}
}
// TypeError: Animal is not a constructor
let myAnimal = new Animal('Kay');
原始函式與箭頭函式比較
原始函式
function greeting() {
console.log('Hello, JavaScript!!');
}
greeting();
箭頭函式
const greeting = () => {
console.log('Hello, JavaScript!!');
};
greeting();
函式僅回傳指定資料
函式本身只是要回傳某個值的話,可以把 return
這個字省略掉,要回傳的資料直接放在箭頭
後方
const greeting = () => console.log('Hello, JavaScript!!');
greeting();
const greeting = () => 'Hello, JavaScript!!';
console.log(greeting()); // 'Hello, JavaScript!!'
// 等同於這樣寫
const greeting = function () {
return 'Hello, JavaScript!!';
};
箭頭函式帶入參數值
const add = (a, b) => a + b;
console.log(add(3, 5));
// 等同於這樣寫
const add = function (a, b) {
return a + b;
};
箭頭函式對 this 的影響
箭頭函式當中的 this
綁定的是是定義時的物件,而不是使用時的物件,所以定義當下 this
指的是哪個物件就會是那個物件,不會隨著時間改變
let id = 21;
let data = {
id: 21,
};
fn.call(data);
arrowFn.call(data);
// 原本的 function
function fn() {
// [fn] Object
console.log(`[fn] ${this.constructor.name}`);
setTimeout(function () {
// [fn.setTimeout] Timeout
console.log(`[fn.setTimeout] ${this.constructor.name}`);
}, 100);
}
// 箭頭函式 Arrow function
function arrowFn() {
// [arrowFn] Object
console.log(`[arrowFn] ${this.constructor.name}`);
setTimeout(() => {
// [arrowFn.setTimeout] Object
console.log(`[arrowFn.setTimeout] ${this.constructor.name}`);
}, 100);
}
this.constructor.name
:這樣子的寫法只是避免在回傳出物件的時候,把整個物件內容給傳出來,而是僅傳出該物件的名稱。
使用 .call(data)
指定在函式都是使用 data
這個物件當作是 this
物件
fn.call(data) 傳統函式
裡面的 setTimeout 執行的時間點是在 Stack
沒有任務時,才從 task queue
拿出來執行,當時的執行環境是 global environment
,所以 this
的綁定會依據當時執行的環境換掉
arrowFn.call(data) 箭頭函式
裡面的 setTimeout 是在 data
物件當成是 this
時候定義的,所以箭頭函式內的 this
會一直綁定為原呼叫的物件
參考資料
- Function - JavaScript | MDN
- JavaScript - call,apply,bind - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
- Function expression - JavaScript | MDN
- [JavaScript] 函數原型最實用的 3 個方法 — call、apply、bind | by realdennis | Medium
- [JS] 箭頭函式(arrow function)和它對 this 的影響 | PJCHENder 未整理筆記
Donate KJ 贊助作者喝咖啡
如果這篇文章對你有幫助的話,可以透過下面支付方式贊助作者喝咖啡,如果有什麼建議或想說的話可以贊助並留言給我
If this article has been helpful to you, you can support the author by treating them to a coffee through the payment options below. If you have any suggestions or comments, feel free to sponsor and leave a message for me!
方式 Method | 贊助 Donate |
PayPal | https://paypal.me/kejyun |
綠界 ECPay | https://p.ecpay.com.tw/AC218F1 |
歐付寶 OPay | https://payment.opay.tw/Broadcaster/Donate/BD2BD896029F2155041C8C8FAED3A6F8 |