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 |