es6語法之解構賦值總結
解構賦值分類:
- 物件的解構賦值;
- 陣列的解構賦值;
- 字串的解構賦值;
- 數值和布林值的解構賦值;
- 函式引數的解構賦值;
細節問題:
- 圓括號;
- 用途;
解構賦值分類
一.物件的解構賦值
let { name, age } = { name: "mike", age: 11 };
console.log(name); //mike
console.log(age); //11
- 物件的解構不同於陣列。陣列中的變數的取值是由他的位置決定的,而物件中的變數必須與屬性同名才能取得值:
let { name, age } = { age: 18, name: "mike" };
console.log(name); //mike
console.log(age); //18
let { bar } = { age: 11, name: "tom" };
console.log(bar); //undefined
2.如果變數的名字和屬性的名字不一致,應該這麼寫:
let { name: N } = { name: "tom" }; console.log(N); //tom let obj = { first: "hello", last: "world" }; let { first: F, last: L } = obj; console.log(F,L); //hello world
實際上,物件的解構賦值的內部機制是:先找到同名屬性,然後再賦值給對應的變數。真正被賦值的是後者。上面的程式碼中first是匹配的模式,F是賦值的變數。
3.和陣列一樣,解構也可以用於巢狀結構的物件:
let obj = { p: [ "hello", { y: "world" } ] }; let { p, p: [ x, { y }] } = obj; console.log(x, y); //hello world console.log(p); //["hello", { y: "world" }] //注意:上面第二個對y屬性的解構賦值中,x和y是變數,p是模式
4.如果要將一個已經宣告的變數用於解構賦值,必須非常小心。
let x;
{ x } = { x: "mike" };
console.log(x); //報錯
上面的程式碼會報錯是因為JavaScript引擎會將{ x }理解成一個程式碼塊,從而發生語法錯誤。正確的做法是將上面的解構賦值程式碼用一個圓括號包起來。
let x;
({ x } = { x: "mike" });
console.log(x); //mike
例子:
let obj = {};
let arr = [];
({ name: obj.prop, age: arr[0] } = { name: "tom", age: 15 });
console.log(obj); //{ prop: "tom" }
console.log(arr); //[15]
5.物件的解構使用預設值:
var {x = 1} = {}; //x=1
var {x, y = 5} = {x: 1}; //x=1,y=5
var {x: y = 3} = {}; //y=3
var {x: y = 7} = {x: 8}; //y=8
6.預設值生效的條件是物件的屬性值嚴格等於undefined:
var {x = 14} = {x: undefined}; //14
var {y = 15} = {y: null}; //null
7.如果解構失敗,變數的值為undefined
let {foo} = {bar: "mike"};
console.log(foo); //undefined
8.如果解構模式是巢狀的物件,而且子物件所在的父屬性不存在,那麼將會報錯。
let {foo: { one }} = {bar: "mike"}; //報錯
9.物件的解構賦值,可以很方便的把現有物件的方法,賦值給變數。
let {cos, sin, tan} = Math;
10.由於陣列本身是特殊的物件,所以可以對陣列進行物件屬性的解構。
let arr = [1, 2, 3];
let {0: first, [arr.length-1]: last} = arr;
console.log(first); //1
console.log(last); //3
二.陣列的解構賦值
1.陣列中的變數按照位置的順序取值:
let [a, b, c] = [1, 2, 3];
console.log(a,b,c); //1 2 3
模式匹配:只要等號兩邊的模式相同,左邊的變數就會被賦予對應的值。
2.巢狀陣列進行解構:
let [one, [[two], three] ] = [7, [[2], 3] ];
console.log(one,two,three); //7 2 3
let [ , , third] = ["a","b","c"];
console.log(third); //c
let [ x, , z ] = [1, 2, 3];
console.log(x,z); //1 3
let [a, ...arr] = [1, 2, 3, 4];
console.log(a); //1
console.log(arr); //[2, 3, 4]
let [a, b, ...c] = ["a"];
console.log(a); //a
console.log(b); //undefined
console.log(c); //[]
3.如果解構不成功,變數的值就是undefined
let [foo] = [];
let [bar, foos] = [1];
console.log(foo, bar, foos); //undefined 1 undefined
4.如果等號的右邊不是陣列,那麼將會報錯:
// 報錯
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
事實上,只要某種資料結構具有 Iterator 介面,都可以採用陣列形式的解構賦值。
5.陣列結構賦值也可以使用預設值:
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
同理,陣列成員嚴格等於undefined,預設值才會生效。
6.如果預設值是一個表示式,那麼這個表示式是惰性求值的,即只有在用到的時候,才會求值。
function f() {
console.log('aaa');
}
let [x = f()] = [1];
上面程式碼中,因為x
能取到值,所以函式f
根本不會執行。
7.預設值可以引用解構賦值的其他變數,但該變數必須已經宣告。
let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined
上面最後一個表示式之所以會報錯,是因為x
用y
做預設值時,y
還沒有宣告。
三.字串的解構賦值
1.字串的解構賦值是將字串轉換為一個類似陣列的物件
let [a, b, c, d, e] = "hello";
console.log(a); //h
console.log(b); //e
console.log(c); //l
console.log(d); //l
console.log(e); //o
2.類似陣列的物件都有一個length屬性,因此可以對這個屬性進行解構賦值
let {length: len} = "hello";
console.log(len); //5
四.數值和布林值的解構賦值
1.解構賦值時,如果等號右邊是數值或布林值,則會先轉為物件
let {toString: str1} = 123;
console.log(str1 === Number.prototype.toString); //true
let {toString: str2} = true;
console.log(str2 === Boolean.prototype.toString); //true
上面程式碼中,數值和布林值的包裝物件都有toString
屬性,因此變數s
都能取到值。
2.解構賦值的規則是,只要等號右邊的值不是物件或陣列,就先將其轉為物件。由於undefined
和null
無法轉為物件,所以對它們進行解構賦值,都會報錯。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
五.函式引數的解構賦值
1.函式的引數也可以使用解構賦值
function add([x, y]){
console.log(x + y);
}
add([1, 2]); //3
2.函式引數的解構也可以使用預設值
function move({x = 0, y = 0} = {}){
console.log([x, y]);
}
move({x: 1, y: 2}); //[1, 2]
move({x: 1}); //[1, 0]
move({}); //[0, 0]
move(); //[0, 0]
3.為函式move
的引數指定預設值,而不是為變數x
和y
指定預設值
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
細節問題
一.圓括號
1.可以使用圓括號的情況只有一種:賦值語句的非模式部分,可以使用圓括號。
[(b)] = [3]; // 正確
({ p: (d) } = {}); // 正確
[(parseInt.prop)] = [3]; // 正確
上面三行語句都可以正確執行,因為首先它們都是賦值語句,而不是宣告語句;其次它們的圓括號都不屬於模式的一部分。第一行語句中,模式是取陣列的第一個成員,跟圓括號無關;第二行語句中,模式是p
,而不是d
;第三行語句與第一行語句的性質一致。
二.用途
1.交換變數的值
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y); //2 1
2.從函式返回多個值
函式只能返回一個值,如果要返回多個值,只能將它們放在陣列或物件裡返回。有了解構賦值,取出這些值就非常方便。
//函式返回陣列
function arr(){
return [1, 2, 3];
}
let [x, y, z] = arr();
console.log(x, y, z); //1 2 3
//函式返回物件
function obj(){
return {
name: "mike",
age: 11
}
}
let {name: N, age: A} = obj();
console.log(N, A); //mike 11
3.函式引數的定義
解構賦值可以方便地將一組引數與變數名對應起來。
// 引數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 引數是一組無次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
4.提取json資料
解構賦值對提取 JSON 物件中的資料,尤其有用。
let jsonData = {
id: 11,
name: "tom",
number: [4, 5]
}
let {id, name, number: N} = jsonData;
console.log(id, name, N); //11 tom [4, 5]