箭頭函式運算式 (Arrow Function expression) 是在 ES6 新增的建立函式語法,這種寫法有著兩個重要的特性:
箭頭函式(Arrow Function)
傳統的函式寫法:
1 2 3 4 5 6 7 8 9 10 11
| let myFunc = function(){ return 1; }
let fn = function(n1, n2){ return n1+ n2; }
myFunc(); fn(1,2);
|
ES6 的箭頭函式寫法:
1 2 3 4 5 6 7
| let myFunc = () => (1);
let fn = (n1, n2) => (n1+n2);
myFunc(); fn(1,2);
|
在使用箭頭函式中,如果函式沒有帶上參數記得加空括號 () ,有參數直接在 () 內填入參數即可。
如果函式最後要回傳值的話,可以省略 return 不寫。
當函式只有一個參數時,不需要使用括號
從上面的例子可以發現,當函式無參數或有兩個以上的參數時,都要加上括號 ( );當函數只有一個參數時,可以省略括號不寫。
1 2 3 4 5 6
|
let fn = (n1) => (n1);
let fn = n1 => n1; fn(1);
|
我們使用括號 () 來定義函式帶入的參數,而大括號 {} 定義函式功能的一些 JavaScript 語句,如果函式有多行語句(表達式)時就要使用 {} , {} 內需自行加入 return
,否則會出現 undefined
:
1 2 3 4 5
| let fn = (n1) => { n1 } let myfunc = (n1) => { return n1; }
fn(1); myfunc(1);
|
匿名函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
const sum = function(a, b) { return a+b; }
const sum_arr = (x, y) => { return x + y; };
let fn = function(){ setTimeout(function(){ console.log("1秒"); },100); }
let fn_arr = function(){ setTimeout(() => { console.log("1秒"); },100); }
sum(1,2); sum_arr(1,2); fn(); fn_arr();
|
指定參數的預設值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function fn(name){ if(name == undefined){ name= "Cyting"; } console.log(name); }
function fn(name ="Cyting"){ console.log(name); }
let fn = (name="Cyting") => { console.log(name); }
fn("Cheng-Yi-Ting!"); fn();
|
箭頭函式的 this
不管是使用傳統的函式寫法或箭頭函式, this 都會存取到 window 物件(不清楚原因的話請先參考之前的文章 JavaScript THIS )。
1 2 3 4 5 6 7 8 9 10
| let fn = function(){ console.log(this); }
let fn2 = () => { console.log(this); }
fn(); fn2();
|
func
和 setTimeout
箭頭函式的 this
均會指向 obj
:
1 2 3 4 5 6 7 8 9 10 11
| const obj = { a:1 }
function func() { console.log(this.a) setTimeout(() => { console.log(this.a) }, 1000)
}
func.call(obj)
|
如果是傳統的函式寫法, setTimeout
的 this
會指向 window
物件:
1 2 3 4 5 6 7 8 9 10
| const obj = { a: 1 }
function func() { console.log(this.a) setTimeout( function() { console.log(this.a) }, 1000) }
func.call(obj)
|
我們可以透過將 this
存在 that
變數中,之後就可以透過 that
存到之前 this
的參照:
1 2 3 4 5 6 7 8 9 10
| const obj = { a: 1 }
function func(){ const that = this setTimeout(function(){ console.log(that.a) }, 1000) }
func.call(obj)
|
也可以透過 .bind()
來強制指定 this
為 () 內的物件,於是可以把 setTimeout
裡面的 this
指定為先前的 this
:
1 2 3 4 5 6 7 8 9
| const obj = { a: 1 }
function func(){ setTimeout(function(){ console.log(this.a) }.bind(this), 1000) }
func.call(obj)
|
傳統函式的 this
是根據呼叫方式的不同而有所不同;箭頭函式的 this
是綁定到其定義時所在的物件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| var name = 'Cheng-Yi-Ting' var obj = { name: 'Cyting', fun1: function () { console.log('1', this.name); setTimeout(() => { console.log('2', this.name); console.log('3', this); }, 1000); }, fun2: () => { console.log('4', this.name); setTimeout(() => { console.log('5', this.name); console.log('6', this); }, 1000); } }
obj.fun1(); obj.fun2();
|
一般函式是建立在 window
底下,所以箭頭函式自然會指向 window
;可以透過將箭頭函式宣告在物件內部,來將 this
指向該物件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var func = function () { var func2 = function () { setTimeout(() => { console.log(this); }, 1000); };
var func3 = { func: func2, value: 1 } func2(); func3.func(); } func();
|
func3()
是呼叫在物件內的函式,因此箭頭函式會是使用它所在的物件。
不可使用箭頭函式的情況
apply, call, bind
函式物件中的 call
、 apply
、 bind
這三個方法,無法覆蓋箭頭函式中的 this
值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let obj = { value: 1 }
const a = () => { console.log(this); }
const b = function () { console.log(this); }
a.call(obj); b.call(obj);
|
建構函式
箭頭函式無法像一般的函式一樣作為建構式使用,使用 new
語法會出現錯誤:
1 2 3 4 5 6
| const Message = (text) => { this.text = text }
const helloMessage = new Message('Hello World!');
|
DOM事件處理函式
在 HTML 中建立一個 button element,在 button 使用 addEventListener 事件監聽器:
1 2 3 4 5 6 7 8 9
| var button = document.querySelector('button'); var fn_arr = () => { console.log(this) };
var fn = function(){ console.log(this) } button.addEventListener('click', fn_arr);
|
使用傳統的寫法,在觸發這個事件時所指稱的對象會從原本的 window
變成按鈕物件;若使用的是箭頭函式,則 this
一樣會是 window
物件。
Prototype 中定義的方法
如果在原型中使用箭頭函式,此時箭頭函式內的 this
會指向 window
,若是在嚴格模式則會是 undefined
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function Person(firstName, lastName, age) { this.firstName = firstName; this.lastName = lastName; this.age = age; }
Person.prototype.log1 = function () {
console.log(this.firstName+' '+this.lastName+ ', age:' + this.age); } Person.prototype.log2 = () => {
console.log(this.firstName+' '+this.lastName+ ', age:' + this.age); }
const roman = new Person('Roman', 'Gonzalez', 18);
roman.log1();
roman.log2();
|
結論
箭頭函式語法
- 沒有參數時要有小括號。
- 只有一個參數時可以省略小括號。
- 若有兩個以上的參數要有小括號。
- 只有一行回傳值可以省略大括號。
箭頭函式限制
- 函式物件中的
call
、 apply
、 bind
這三個方法,無法覆蓋箭頭函式中的 this
值。
- 不可作為建構式使用,會在使用
new
時候拋出錯誤。
- 箭頭函式並沒有原型(prototype)屬性。
- 沒有一般函式有的隱藏 arguments 物件。
- 箭頭函式不能當作 generators 使用,使用
yield
會產生錯誤。
參考文獻
https://dotblogs.com.tw/shihgogo/2017/12/11/111122
https://ithelp.ithome.com.tw/articles/10185221
https://ithelp.ithome.com.tw/articles/10227798
https://pjchender.blogspot.com/2017/01/es6-arrow-function.html?m=1
https://wcc723.github.io/javascript/2017/12/21/javascript-es6-arrow-function/
https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/arrow_function.html