1. 程式人生 > >變數的解構賦值

變數的解構賦值

解構:按照一定模式,從陣列和物件中提取值,對變數進行賦值。

1.陣列的解構賦值

基本用法    

之前的賦值形式為直接指定值,例如let a = 1。ES6允許寫成let [a,b,c] = [1,2,3],從陣列中提取值,按照對應的位置,對變數賦值,只要等號兩邊的模式相同,左邊的變數就會被賦予相應的值。
  • 如果解構不成功,變數的值就會等於undefined
  • 等號左邊的模式只匹配等號右邊的一部分陣列,這是不完全解構,但解構依然成功
  • 如果等號右邊不是陣列(不是可遍歷的結構,比如數值、布林值、NaN、undefined、null、{}等),則會報錯
  1. //巢狀陣列解構
  2. let [foo,[[bar],
    baz]]=[1,[[2],3]];
  3. foo // 1
  4. bar // 2
  5. baz // 3
  6. let [,, third]=["foo","bar","baz"];
  7. third // "baz"
  8. let [x,, y]=[1,2,3];
  9. x // 1
  10. y // 3
  11. let [head,...tail]=[1,2,3,4];
  12. head // 1
  13. tail // [2, 3, 4]
  14. let [x, y,...z]=['a'];
  15. x // "a"
  16. y // undefined
  17. z // []
  18. //解構不成功
  19. let [foo]=[];
  20. let [bar, foo]=[1];//foo都等於undefined
  21. //不完全解構
  22. let [x, y]=[1,2,3];
  23. x // 1
  24. y // 2
  25. let [a,[
    b], d]=[1,[2,3],4];
  26. a // 1
  27. b // 2
  28. d // 4
  29. // 報錯
  30. let [foo]=1;
  31. let [foo]=false;
  32. let [foo]=NaN;
  33. let [foo]=undefined;
  34. let [foo]=null;
  35. let [foo]={};
    對於Set結構,也可以使用陣列的解構賦值(set資料結構類似於陣列,但是成員值是唯一的且沒有重複值)。
  1. let [x, y, z]=newSet(['a','b','c']);
  2. x // "a"

預設值

    解構賦值允許指定預設值,但ES6內部使用嚴格相等運算子(===)來判斷一個位置是否有值,即如果變數是嚴格等於undefined,預設值才生效(理解為變數沒有被賦值才需要用到預設值)。
  1. //指定預設值
  2. let [foo =true]=[];
  3. foo // true
  4. let [x, y ='b']=['a'];// x='a', y='b'
  5. let [x, y ='b']=['a',undefined];// x='a', y='b'
  6. //預設值不生效
  7. let [x =1]=[undefined];
  8. x // 1
  9. let [x =1]=[null];
  10. x // null,因為null不嚴格等於undefined
    如果預設值是一個表示式,那麼這個表示式是惰性求值的,只有在用到的時候才會求值。
  1. function f(){
  2. console.log('aaa');
  3. }
  4. let [x = f()]=[1];//x為1,因為x能夠取到值,函式f不會執行,即變數賦值嚴格等於undefined時,預設值才會生效
    預設值可以引用解構賦值的其他變數,但是該變數必須已經宣告。
  1. let [x =1, y = x]=[];// x=1; y=1
  2. let [x =1, y = x]=[2];// x=2; y=2
  3. let [x =1, y = x]=[1,2];// x=1; y=2
  4. let [x = y, y =1]=[];// ReferenceError,x賦值為undefined,預設值為y,但y沒有宣告,報錯

2.物件的解構賦值

基本用法    

    與陣列解構賦值不同的是,陣列的元素是按次序排列的,物件的屬性沒有次序,變數必須與屬性同名,才能取到正確的值,物件解構賦值的內部機制是,先找到同名屬性,然後再賦值給對應的變數。
  1. let { foo: baz }={ foo:"aaa", bar:"bbb"};
  2. baz // "aaa"
  3. foo // error: foo is not defined
  4. foo是匹配的模式,baz才是變數,被賦值的是變數
    變數名和屬性名一致時,可以簡寫:
  1. let { bar, foo }={ foo:"aaa", bar:"bbb"};
  2. foo // "aaa"
  3. bar // "bbb"
  4. let { baz }={ foo:"aaa", bar:"bbb"};
  5. baz // undefined
    物件的解構賦值的變數宣告和賦值是一體的,let和const變數不允許重新宣告。
  1. let foo;
  2. let {foo}={foo:1};// SyntaxError: Duplicate declaration "foo"
  3. let baz;
  4. let {bar: baz}={bar:1};// SyntaxError: Duplicate declaration "baz"
  5. let foo;
  6. ({foo}={foo:1});// 成功
  7. let baz;
  8. ({bar: baz}={bar:1});// 成功,圓括號必須有,解析器會將圓括號為首理解成程式碼塊,而不是賦值語句
    解構也可以用於巢狀解構的物件。
  1. let obj ={};
  2. let arr =[];
  3. ({ foo: obj.prop, bar: arr[0]}={ foo:123, bar:true});
  4. obj // {prop:123}
  5. arr // [true]

預設值

  • 物件的解構也可以指定預設值,生效的條件是物件的屬性值嚴格等於undefined
  • 如果解構失敗,變數的值等於undefined
  • 如果解構模式是巢狀的物件,而且子物件所在的父屬性不存在,會報錯
  1. var{x =3}={};
  2. x // 3
  3. var{x, y =5}={x:1};
  4. x // 1
  5. y // 5
  6. var{x:y =3}={};
  7. y // 3
  8. var{x:y =3}={x:5};
  9. y // 5
  10. var{ message: msg ='Something went wrong'}={};
  11. msg // "Something went wrong"
  12. // 報錯,foo對應子物件,bar是子物件的屬性,foo此時為undefined,取子屬性就會報錯
  13. let {foo: {bar}} = {baz: 'baz'};
  14. 相當於let {foo: {bar: bar}} = {baz: 'baz'};
    物件的解構賦值,可以將現有的方法,賦值到某個變數。
  1. let { log, sin, cos }=Math;
    陣列的本質是物件,可以對陣列進行物件屬性的解構。
  1. 對陣列進行物件解構,arr.length-1對應索引為2,所以值為3
  2. let arr =[1,2,3];
  3. let {0: first,[arr.length -1]: last}= arr;