很多人(可能其實只有我自己),在學完基礎的 JS 之後,為了跟風或者是找工作,一腳踏入進入 React 的世界,結果卻發現看了範例卻傻了,根本不知道在幹嘛。不是那種慢慢理解就可以的狀況,是連語法都看不懂。
其實也沒有那麼複雜,就是 es6 的語法不熟而已, es6 相較於之前的 javascript 的語法根本就是一個大躍進。各種以前想像不到的神奇都出現了,有些有用到,有些沒用到(很快就會開始用到)。今天講的內容不敢說很常用(相較於 const, let, arrow function 等等的語法起來的確沒有那麼常用),但是可以幫你省下很多繁瑣的過程。
分別是
- Destructuring assignment
- Spread Syntax
- Rest Parameter
YA 那就開始囉。
Destructuring assignment
中文應該稱作解構賦值吧。聽起來超帥的,很像某個技能名稱。
先來看 code 好了
let [a, b] = [10, 20];
console.log(a, b) // 10, 20
let {name, phone} = {name: 'Jack', phone: '0920123321'};
console.log(name, phone) // 'Jack' '0920123321'
看了之後就知道其實沒有那麼複雜,就是把 Array 或者是 Object 拆分成獨立的變數的一種方法而已。
那下面就來比較詳細的介紹。
array 的 Destructuring
其實光上面的範例看應該可以看出一些端倪。我們宣告一個有兩個變數 a, b 的 array。
let [a, b]
然後再 assign =
給另一個已經有值的 array。
let [a, b] = [10, 20];
然後 array 中的 a, b 就被賦值
let [a, b] = [10, 20];
console.log(a, b) //10 20
//相當於
// let a = 10;
// let b = 20;
變數會依照順序對應到 array 中的值。雖然一開始看到可能會有:「What?你怎麼把奇怪的東西兜在一起了?」但習慣之後應該算是蠻直觀的。
object 的 Destructuring
然後在 Object 中也有解構賦值。來試試吧,首先向剛剛的 array 一樣在 object 中放入你要的變數。
let {c, d} = {name: 'Jack', phone: '0920123321'}
只不過是把 [ ]
換成 { }
而已嘛,簡單。看我 print 出來。
let {c, d} = {name: 'Jack', phone: '0920123321'};
console.log(c, d) //undefined undefined
什麼!為什麼是 undefined!搞屁啊!
array 利用順序來對應哪個變數名稱對應到哪個值,那 Object 也應該要有個東西對應才對,然而 object 內容不像 array 一樣,是沒有順序的,所以我們必須有個東西作為對應,那東西就是 Object 的 key。
因此 Object 的變數名稱必須放在 value裡面,像是:
const obj = { name: 'Jack', phone: '0920123321' };
let { name: JackName, phone: JackPhone } = obj;
console.log(JackName, JackPhone) //'Jack' '0920123321'
欸不是!剛剛的範例也沒看你把要賦值的變數名稱放在 value 啊!為什麼還是可以用呢?
let { name, phone } = { name: 'Jack', phone: '0920123321' };
console.log(name, phone);
先別著急,還記得 object 有一個用法嗎?如果你要把變數的名稱作為 key,變數的值作為 value,就會有一個很方便的寫法:你只要直接把變數放進 object 就好。
let name = "Mandy";
let phone = "03-0303-3030";
let mom = { name, phone }
console.log(mom.name, mom.phone); //Mandy 03-0303-3030
Object 的 Destructuring 也是一樣的道理喔。如果你要賦值的變數名稱跟 key 相同,那你也不用在打一次
let {name, phone} = {name: 'Mandy', phone: '03-0303-3030'};
應用篇
其實剛剛的用法就已經涵蓋了大概百分之 70 的應用面了。這裡會提到一些 MDN 上面比較有趣的例子,雖然好像自己看也很簡單就是了...
值的互換
最早如果要交換的話可能都要有個第三方的變數來做存放
let a = 3;
let b = 5;
//互換
let c = a;
a = b;
b = c;
console.log(a, b) //5 3
有了解構賦值之後就好棒棒!
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
array 裡面也可以這樣用喔
const arr = [1,2,3];
[arr[2], arr[1]] = [arr[1], arr[2]];
console.log(arr); // [1,3,2]
這部分應該算是蠻好理解的
array 的 destructring 忽略中間值會怎麼樣?
如果是下面這樣的話,會出現什麼?
let [a, , b] = [1, 2, 3]
console.log(a, b) //1 3
就是忽略中間的值,蠻直覺的吧
不宣告 object 使用 object 的 destructring
這個我自己也覺得蠻酷的。使用 array 時可以這樣用
let a, b;
[a, b] = [1, 2]
console.log(a, b) //1, 2
先進行宣告,再賦值。
但是如果用在 object 呢?
let a, b;
{a, b} = {a: 1, b: 2} //SyntaxError: Unexpected token '='
會跑出 error 喔,因為宣告 object 的符號 {}
和區分 block 的符號 {}
是一樣的。在這部分會不知道說你要宣告 object 還是要區分出 block。
所以必須在外面加上一個 ( )
let a, b;
({a, b} = {a: 1, b: 2})
console.log(a, b)// 1, 2
這樣一來就沒問題了
巢狀的 destructring
const metadata = {
title: 'Scratchpad',
translations: [
{
locale: 'de',
localization_tags: [],
last_edit: '2014-04-14T08:43:37',
url: '/de/docs/Tools/Scratchpad',
title: 'JavaScript-Umgebung'
}
],
url: '/en-US/docs/Tools/Scratchpad'
};
let {
title: englishTitle, // rename
translations: [
{
title: localeTitle, // rename
},
],
} = metadata;
簡單說就是包在裡面,這也是沒問題的。
Spread Syntax
function sum (a, b, c) {
return a + b + c
}
const nums = [1, 2, 3]
console.log(sum(...nums))
spread 可以"展開" 一個 array,這樣講很難理解,更何況後面還會加入 object 的 spread。後來想到一個最好的理解方式。
簡單說,就是把 array 的 []
去掉。
[1, 2, 3] => 1, 3, 5
看看下面的情境
[1, 2, 3, 4, 6, ...[2, 4, 5]] = [1, 2, 3, 4, 6, 2, 4, 5]
就是把 [2, 4, 5]
的 []
去掉,變成 2, 4, 5
然後放進 [1, 2, 3, 4, 6]
裡面
這個東西可以用在兩個地方:
- 放入參數
- 分解 array
https://tc39.es/process-document/
Rest Parameters
英文字面上解釋起來就是剩餘參數。會在 function 中使用。可以把剩下的參數,變成一個 array。個人好像比較少用到。其實只是我不會用
基本形式
function f(a, b, ...theArgs) {
// ...
}
這是最基本的形式,來看看範例
function f(a, b, ...theArgs) {
console.log("a", a);
console.log("b", b);
console.log("theArgs", theArgs);
}
f(1, 2, 3, 4, 5)
//"a" 1
//"b" 2
//"theArgs" [3, 4, 5]
f(1, 2, 3, 4, 5, 6, 7, 8)
//"a" 1
//"b" 2
//"theArgs" [3, 4, 5, 6, 7, 8]
會把剩下的參數都放進去。下面是一點應用建立一個加法的計算機,把所有的參數的 sum up 算出來。
function add(a, b, c) {
return a + b + c
}
add (1, 2, 3) //6
但是我們遇到一個問題,這樣只能加三個數字,理想的加法計算機當然是給多少數字都要很豪邁地把它加起來。不管 input 是一個數字還是一百個數字。
像這樣的晴晴我們不確定說會有多少參數,我們就會利用 Rest Parameter 全部放進 array 裡面,這樣不管有幾個參數,都可以使用。
function add(...args) {
return [args, args.reduce((acc, el) => el + acc, 0 )}
}
add(1, 5, 4) // [[1, 5, 4], 10]
add(1, 5, 4, 2, 1) //[[1, 5, 4, 2, 1], 13]
是不是很棒?當然使用情境也不止這種,簡單來說,他會把剩下的參數都放進一個 array 裡面。不過要注意的是,Rest Parameter 只能放在最後面。
function f(...theArgs, a, b) {
// ...
}
//請不要以為他會把最後兩個變成 a 跟 b 然後前面的都放進 theArgs
因為這東西跟上面的 Spread Syntax 很像都是 ...
,自己很常搞混。但其實沒那麼複雜,==Rest Parameter 只會在 function 的建構裡面看到她。==
這裡有個比較複雜的範例,綜合了 Destructure 還有 Rest Parameter
function f(...[a, b, c]) {
return a + b + c;
}
f(1) // NaN (b and c are undefined)
f(1, 2, 3) // 6
f(1, 2, 3, 4) // 6 (the fourth parameter is not destructured)
他作了以下事情
function f(...args) {
// 把所有的參數集中到一個 array,可以想成:
args = [a, b, c]
// 然後解構賦值
}
這樣想就單純很多了,只是放在一起看起來牛逼而已。
Arguments.property
很久很久古早以前,有一個 function 內建的 property arguments
,裡面是一個 Object ,內容有 function 中所有的變數。
function test(...args) {
console.log(arguments)
console.log(args)
return args.reduce((acc, el) => el + acc, 0 )
}
/*
[object Arguments] {
0: 1,
1: 2,
2: 3,
3: 4,
4: 5
}
[1, 2, 3, 4, 5]
*/
只是一個出來的是 object 另一個是 Array。
Note: If you're writing ES6 compatible code, then rest parameters should be preferred.
不過現在 MDN 是比較推薦使用 rest parameters ,畢竟 array 自帶 map,方便許多,不用再使用 Array.from()
處理一遍。
但這兩個東西還是有差距,讓我們翻到講義第八頁 讓我們看看原文。
- rest parameters are only the ones that haven't been given a separate name (i.e. formally defined in function expression), while the arguments object contains all arguments passed to the function;
- the arguments object is not a real array, while rest parameters are Array instances, meaning methods like sort, map, forEach or pop can be applied on it directly;
- the arguments object has additional functionality specific to itself (like the callee property).
- Rest Parameters 只會把剩下的放進去,而不是全部
- Arguments 不是 array 他只是一個類 Array (有編號,有 length 的 Object );不過 Rest Parameters 卻是個貨真價實的 Array ,
map
,forEach
等等的東西應有盡有。 - argument 也不是單純的 Object 裡面還有一些 callee 等等的東西。
大概就是這樣,argument 不太好用,而且有雜七雜八的東西,所以才比較堆建 Rest parameter 吧。
結語
這東西也不用刻意去記,看久了自然而然就會使用了,每次在 coding 的時候都多用一點新的語法很快就會記熟了。當初 ES6 甚麼都不懂然後就一腳踏入 React 就直接被炸飛,因為有用到的地方實在太多了,想不懂都不行,而且這部分應該是 ES6 裡面很入門的部分。
Big guy is John。感謝大家的收看~