1. 程式人生 > >《深入理解ES6》——物件解構和陣列解構

《深入理解ES6》——物件解構和陣列解構

為何使用解構功能

    在ES5及早期版本中,開發者們為了從物件和陣列中獲取特定資料並賦值給變數,編寫了許多看起來同質化的程式碼,如下:

let options = {
    repeat:true,
    save:false
};
//從物件中取資料
let repeat = options.repeat,
    save = options.save;

   這段程式碼從options物件中提取了repeat和save的值並將其儲存為同名區域性變數,提取的過程極為相似,想象一下,如果你要提取更多變數,則必須依次編寫類似的程式碼來為變數賦值,如果其中還包含巢狀結構,只靠遍歷是找不到真實資訊的,必須要深入挖掘整個資料結構才能找到所需資料。

物件解構

    物件解構的語法形式是在一個賦值操作左邊放置一個物件字面量,如:

let node = {
    type:"Identifier",
    name:"foo"
};
let {type,name} = node;
console.log(type);//"Identifier"
console.log(name);//"foo"

    在這段程式碼中,node.type的值被儲存在名為type的變數中;node.name的值被儲存在名為name的變數中。

注意:如果使用var、let、const解構宣告變數,必須要提供初始化程式(也就是等號右側的值),否則會導致程式丟擲語法錯誤

解構賦值

    同樣可以在給變數賦值時使用解構語法,如下,在定義變數之後想要修改他們的值,可以這樣:

let node = {
    type:"Identifier",
    name:"foo"
},

type = "Literal",
name = 5;

//使用解構語法為多個變數賦值
({type,name} = node);

console.log(type);//"Identifier"
console.log(name);//"foo"

    在這個示例中,宣告變數type和name時初始化了一個值,在後面的幾行中,通過解構賦值的方法,從node物件讀取相應的值重新為這兩個變數賦值。注意:一定要用一對小括號包裹解構賦值語句,javascript引擎將一對開放的花括號視為一個程式碼塊,而語法規定,程式碼塊不能出現在賦值語句的左側,新增小括號後可以將塊語句轉化為一個表示式,從而實現整個解構賦值的過程

預設值

    使用解構賦值表示式時,如果指定的區域性變數名稱在物件中不存在,那麼這個區域性變數會被賦值為undefined,如下:

let node = {
    type:"Identifier",
    name:"foo"
};
let {type,name,value} = node;
console.log(type);//"Identifier"
console.log(name);//"foo"
console.log(value);//undefined

    當指定的屬性不存在時,可以隨意定義一個預設值,在屬性名稱後新增一個等號(=)和相應的預設值即可:

let node = {
    type:"Identifier",
    name:"foo"
};
let {type,name,value = true} = node;
console.log(type);//"Identifier"
console.log(name);//"foo"
console.log(value);//true

為非同名區域性變數賦值

    到目前為止的每一個例項中,解構賦值使用的都是與物件屬性同名的區域性變數,例如,node.type的值被儲存在了變數type中。但如果你希望使用不同命名的區域性變數來儲存物件屬性的值,ES6中的一個擴充套件語法可以滿足:

let node = {
    type:"Identifier",
    name:"foo"
};
let {type:localType,name:localName} = node;
console.log(localType);//"Identifier"
console.log(localName);//"foo"

    當使用其他變數名進行賦值時也可以新增預設值,只需在變數名後新增等號和預設值即可:

let node = {
    type:"Identifier"
};
let {type:localType,name:localName = "bar"} = node;
console.log(localType);//"Identifier"
console.log(localName);//"bar"

巢狀物件解構

let node = {
    type:"Identifier",
    name:"foo",
    loc:{
        start:{
          line:1,
          column:1
        },
        end:{
          line:1,
          column:4
        }
    }
};

let {loc:{start}} = node;
console.log(start.line);//1
console.log(start.column);//1

    在這個示例中,我們在解構模式中使用了花括號,其含義為在找到node物件中的loc屬性後,應當深入一層繼續查詢start屬性。更進一步,也可以使用一個與物件屬性名不同的區域性變數名:

let node = {
    type:"Identifier",
    name:"foo",
    loc:{
        start:{
          line:1,
          column:1
        },
        end:{
          line:1,
          column:4
        }
    }
};
//提取node.loc.start
let {loc:{start:localStart}} = node;
console.log(localStart.line);//1
console.log(localStart.column);//1

陣列解構

    與物件解構的語法相比,陣列解構就簡單多了,它使用的是陣列字面量,且解構操作全部在陣列內完成,而不是像物件字面量語法一樣使用物件的命名屬性:

let colors = ["red","green","blue"];
let [firstColor,secondColor] = colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"

    在這段程式碼中,我們從colors陣列中解構出了"red"和"green"這兩個值,並分別儲存在變數firstColor和變數secondColor中。在陣列解構語法中,我們通過值在陣列中的位置進行選取,且可以儲存在任意變數中,未顯式宣告的元素都會直接被忽略。在這個過程中,陣列本身不會發生任何變化。

    在解構模式中,也可以直接省略元素,只為感興趣的元素提供變數名。比如,如果你只想取陣列中的第三個值,則不需要提供第一個和第二個元素的變數名稱:

let colors = ["red","green","blue"];
let [ ,,thirdColor] = colors;
console.log(thirdColor);//"blue"

解構賦值

    陣列解構也可用於賦值上下文,但不需要用小括號包裹表示式,這一點與物件解構的約定不同。

let colors = ["red","green","blue"],
    firstColor = "black",
    secondColor = "purple";
[firstColor,secondColor] = color;
console.log(firstColor);//"red"
console.log(secondColor);//"green"

    陣列解構還有一個獨特的用例:交換兩個變數的值。在ES5中交換兩個變數的值需要引入第三個臨時變數,但在ES6的陣列解構中,就不再需要額外的變量了,如下:

let a = 1,
    b = 2;

[a,b] = [b,a];

console.log(a);//2
console.log(b);//1

預設值

    也可以在陣列解構賦值表示式中為陣列中的任意位置新增預設值,當指定位置的屬性不存在或其值為undefined時使用預設值:

let colors = ["red"];
let [firstColor,secondColor = "green"] = colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"

巢狀陣列解構

let colors = ["red",["green","lightgreen"],"blue"];

let [firstColor,[secondColor]] = colors;

console.log(firsrColor);//"red"
console.log(secondColor);//"green"

    在此示例中,變數secondColor引用的事colors陣列中的值"green",該元素包含在陣列內部的另一個數組中,所以secondColor兩側的方括號是一個必要的解構模式。同樣,在陣列中也可以無限深入去解構,就像在物件中一樣。

不定元素

    在陣列中,可以通過…語法將陣列中的其餘元素賦值給一個特定的變數,如下:

let colors = ["red","green","blue"];

let [firstColor,...restColors] = colors;

console.log(firstColor);//"red"
console.log(restColors.length);//2
console.log(restColors[0]);//"green"
console.log(restColors[1]);//"blue"

注意:在被解構的陣列中,不定元素必須為最後一個條目,在後面繼續新增逗號會導致程式丟擲語法錯誤。

混合解構

    可以混合使用物件解構和陣列解構來建立更多複雜的表示式,如此一來,可以從任何混雜著物件和陣列的資料解構中提取你想要的資訊:

let node = {
    type:"Identifier",
    name:"foo",
    loc:{
        start:{
          line:1,
          column:1
        },
        end:{
          line:1,
          column:1
        }
     },
     range:[0,3]
};

let {
    loc:{start},
    range:[startIndex]
} = node;

console.log(start.line);//1
console.log(start.column);//1
console.log(startIndex);//0

    這段程式碼分別將node.loc.start和node.range[0]提取到變數start和startIndex中。記住:解構模式中的loc:和range:僅代表他們在物件中所處的位置,也就是該物件的屬性。