Day26 | JS 箭頭函式
❒ 箭頭函式架構
- 可把
{}
大括號省略。- 箭頭函式後的
{}
是作為箭頭函式裡面的程式碼片段的範圍使用,並不是物件實字中使用的{}
大括號。所以如果箭頭函式要回傳一個物件內容,須於{}
外層加上()
包覆 →({})
。
- 箭頭函式後的
- 如果程式碼內容為表達式 ( 會回傳值 ),沒有其他內容就可以做縮寫「 省略
{}
大括號 &return
」。 - 如果只有一個參數,可省略
()
括號,但如果沒有參數要保留()
括號。 - 如果大括號內有多行程式,建議不要省略
{}
大括號 &return
。
1 | // 箭頭函式回傳裡面的物件 |
❒ 箭頭函式與傳統函式差異
- 箭頭函式沒有
argument
這個參數。 - 箭頭函式沒有自己的
this
,所以它的this
會指向它的外層。 - 箭頭函式無法透過
call
,apply
,bind
重新給予this
。 - 箭頭函式不能當建構函式使用。
➊ 箭頭函式沒有 argument
這個參數
傳統函式在執行時會自動帶上 argument
這個參數,但箭頭函式沒有 argument
這個參數。
範例 1. 傳統函式
1 | const nums = function() { |
範例 2. 箭頭函式
1 | const nums = () => { |
會顯示錯誤訊息 Uncaught ReferenceError: arguments is not defined at nums
➤ 其餘參數:解決箭頭函式沒有 argument
的方式
有時候也會遇到想要取出沒列出的參數,可使用「 其餘參數 」的方式 …變數名稱
。
1 | const nums = (...ary) => { |
- 使用其餘參數後,展開後可見原型 Property 一樣是陣列,可以使用所有陣列的方法,和
argument
參數有些微不同。
➋ This 綁定的差異
箭頭函式沒有自己的 this
,所以它的 this
會指向它外層。
範例 1.
1 | var myName = '全域'; |
解析:
因為箭頭函式沒有自己的 this
,所以 setTimeout
裡的 this
就會指向它外層的 person
下的 myName
。
範例 2.
1 | var myName = '全域'; |
解析:
callName
調整成箭頭函式,因為箭頭函式沒有自己的this
,所以會往外找外層的myName
。- 答案:1、2 為
全域
,3 為 window。
範例 3. this 不同,導致 DOM 的 this 也會指向不同位置
1 | // 使用傳統函式 |
this
會指向p
段落。
1 | // 使用箭頭函式 |
- 箭頭函式
this
會指向window
,因為箭頭函式沒有自己的this
它會指向外層。
➌ 無法透過 call, apply, bind 重新給予 this
1 | const family = { |
- 傳統函式透過
call
可把另外一段函式傳入,作為它的還是函式執行的this
。 - 箭頭函式
family
用call
的方式傳入,this
會指向全域,因為箭頭函式的this
無法透過call
,apply
,bind
重新給予。
❹ 箭頭函式不能當建構函式使用
範例 1. 查看傳統函式與箭頭函式的 prototype ( 原型 )
1 | const Fn = function (a) { |
- 這兩段拿來做建構函式使用,使用建構函式時會使用
prototype
來新增一些方法,但因「 箭頭函式不具有prototype
所以是不能拿來當建構函式使用 」。所以當ArrowFn
要新建建構函式就會出現錯誤訊息Uncaught TypeError: ArrowFn is not a constructor
。
關於建構式可參考:鐵人賽:JavaScript 建構式
❒ 箭頭函式常見問題
常見錯誤寫法 1
1 | const ArrFn = () => { |
此方式不能直接回傳物件實字,會顯示錯誤訊息:
Uncaught SyntaxError: Unexpected token '}’
箭頭函式後的
{}
是作為箭頭函式裡面的程式碼片段的範圍使用,並不是物件實字中使用的{}
大括號。所以如果箭頭函式要回傳一個物件內容,須於{}
外層加上()
包覆 →({})
。1
2
3
4
5// 正確寫法
const ArrFn = () => ({
data: 1,
});
console.log(ArrFn()); // 就可正確回傳裡面的物件
常見錯誤寫法 2. 判斷式後方不能接箭頭函式
1 | let num = 0; |
這種判斷式後方不能使用箭頭函式,會出現錯誤訊息
Uncaught SyntaxError: Malformed arrow function parameter list
。正確寫法需使用傳統函式或是如上一個範例用
()
包覆。1
2
3
4
5
6
7
8
9
10// 正確寫法 --1
// numFn 右方的 num 是假值(上方定義 num為0所以會直接執行後方函式),回傳函式表達式中的 1
let num = 0;
const numFn = num || function() { return 1; }
console.log(numFn());
// 正確寫法 --2
let num = 0;
const numFn = num || (() => 1);
console.log(numFn());
常見錯誤寫法 3
1 | const person = { |
會印出
undefined
。因為箭頭函式沒有自己的this
,callName
使用箭頭函式裡面的this
會指向全域,全域並沒有muName
。所以如果要取得小明
,callName
就要使用傳統函式。1
2
3
4
5
6
7const person = {
myName: '小明',
callName: function (){
console.log(this.myName);
}
}
person.callName();
常見錯誤寫法 4. 箭頭函式不能作建構函式使用
1 | const Fn2 = function (a) { |
第一行使用傳統函式作建構函式使用。第二行在
Fn2
函式的prototype
下新增一個原型方法protoFn
,這個原型方法使用建構函式來建立。console.log(newObj);
可正確查到Fn2
原型 (prototype
) 下的protoFn
方法。但實際在執行時console.log(newObj.protoFn());
所得到的值會是空的。
為什麼無法得到
newObj
下面的name
,而是取到空值?主要是箭頭函式指向和傳統函式不同,所以
Fn2.prototype.protoFn
裡的this
指向是全域window
而非第一行Fn2
。![截圖](https://ithelp.ithome.com.tw/upload/images/20221011/20119743agmUs6yGMv.png)1
2
3
4
5
6
7
8
9
10const Fn2 = function (a) {
this.name = a;
}
// 調整程式碼看看裡面的this
Fn2.prototype.protoFn = () => {
return this;
}
// 實體化
const newObj = new Fn2('函式');
console.log(newObj.protoFn()); // window正確寫法,把
Fn2.prototype.protoFn
使用傳統函式來建構,可見this
指向為第一行的Fn2
。![截圖](https://ithelp.ithome.com.tw/upload/images/20221011/20119743hoJB77fPfs.png)1
2
3
4
5
6
7
8
9const Fn2 = function (a) {
this.name = a;
}
Fn2.prototype.protoFn = function() {
return this;
}
// 實體化
const newObj = new Fn2('函式');
console.log(newObj.protoFn());
❒ 箭頭函式實戰用法
實戰 1. 搭配陣列方法
1 | // 陣列雙倍 |
map
很適合用在陣列裡所有的值都需要調整的時候,因為 map
會透過函式所回傳的值組成一個新的陣列。
實戰 2. 平均值 加總
1 | // 傳統函式寫法 |
average()
此函式會將傳入的參數 (average(1, 2, 3, 4, 5)
) 全部取出,我們使用arguments
這個參數。由於arguments
為類陣列沒有所有陣列的方法,所以Array.from
使用將它轉為純陣列。
箭頭函式寫法
1 | const average = (...num) => num.reduce((acc, curr) => acc + curr, 0) / num.length; |
- 因為箭頭函式沒有
argument
的方式,所以可使用其餘參數來解決無法取出沒有列出的參數問題。
實戰 3. 物件內 this
1 | // 傳統函式 |
- 記得先載入 jQuery CDN 才可運作
https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js
調整成箭頭函式
1 | // 箭頭函式寫法 |
- 箭頭函式沒有自己的
this
,所以把success
後方調整成箭頭函式後,裡面的this
會指向外層作用域getData
,而基於getData
是由person
呼叫所以this
會指向person
。success
內原本的vm
可修改成this
,const vm = this;
可刪除。
參考資訊
- JavaScript 必修篇 - 前端修練全攻略
- JavaScript 核心篇
- 鐵人賽:JavaScript 建構式
- JavaScript 陣列處理方法 [filter(), find(), forEach(), map(), every(), some(), reduce()]
- 30 SECONDS OF KNOWLEDGE