es6學(xué)習(xí)筆記 - 解構(gòu)賦值

什么是解構(gòu)賦值

解構(gòu)賦值允許你使用類似數(shù)組或?qū)ο笞置媪康恼Z(yǔ)法將數(shù)組和對(duì)象的屬性賦給各種變量伙狐。這種賦值語(yǔ)法極度簡(jiǎn)潔涮毫,同時(shí)還比傳統(tǒng)的屬性訪問(wèn)方法更為清晰瞬欧。
通常來(lái)說(shuō),我們?cè)L問(wèn)數(shù)組的元素的時(shí)候是這樣子的:

    var first = someArray[0];
    var second = someArray[1];
    var third = someArray[2];

使用解構(gòu)賦值賦值則會(huì)變得比較簡(jiǎn)單并且直觀:

    var [first, second, third] = someArray;

SpiderMonkey(Firefox的JavaScript引擎)已經(jīng)支持解構(gòu)的大部分功能罢防,但是仍不健全艘虎。你可以通過(guò)bug 694100跟蹤解構(gòu)和其它ES6特性在SpiderMonkey中的支持情況。

數(shù)組和迭代器的解構(gòu)

以上是數(shù)組解構(gòu)的簡(jiǎn)單例子咒吐,語(yǔ)法的形式為:

// [變量1,變量2,...,變量N] = 數(shù)組
[ variable1, variable2, ..., variableN ] = array;

這將為variable1到variableN的變量賦予數(shù)組中相應(yīng)元素項(xiàng)的值野建。如果你想在賦值的同時(shí)聲明變量,可在賦值語(yǔ)句前加入var恬叹、let或const關(guān)鍵字候生,例如:

    var [ variable1, variable2, ..., variableN ] = array;
    let [ variable1, variable2, ..., variableN ] = array;
    const [ variable1, variable2, ..., variableN ] = array;

事實(shí)上,用變量來(lái)描述并不恰當(dāng)绽昼,因?yàn)槟憧梢詫?duì)任意深度的嵌套數(shù)組進(jìn)行解構(gòu):

var [foo, [[bar], baz]] = [1, [[2], 3]];
    console.log(foo);   // => 1
    console.log(bar);   // => 2
    console.log(baz);   // => 3

此外唯鸭,你可以在對(duì)應(yīng)位留空來(lái)跳過(guò)被解構(gòu)數(shù)組中的某些元素:

var [,,third] = ["foo", "bar", "baz"];
console.log(third);  //  => "baz"

而且你還可以通過(guò)“不定參數(shù)”模式捕獲數(shù)組中的所有尾隨元素:

var [head, ...tail] = [1, 2, 3, 4];
 console.log(head);  // => 1    
console.log(tail);   // => [2, 3, 4]

當(dāng)訪問(wèn)空數(shù)組或越界訪問(wèn)數(shù)組時(shí),對(duì)其解構(gòu)與對(duì)其索引的行為一致硅确,最終得到的結(jié)果都是:undefined目溉。

console.log([][0]); // =>undefined
var [missing] = [];    
console.log(missing); // => undefined    

請(qǐng)注意,數(shù)組解構(gòu)賦值的模式同樣適用于任意迭代器:

function* fibs() {   // 生成器函數(shù)
      var a = 0;
      var b = 1;
      while (true) {
        yield a;    // yield: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/yield
        [a, b] = [b, a + b];
      }
    }
    var [first, second, third, fourth, fifth, sixth] = fibs();
    console.log(sixth);  // =>5
對(duì)象的解構(gòu)

通過(guò)解構(gòu)對(duì)象菱农,你可以把它的每個(gè)屬性與不同的變量綁定缭付,首先指定被綁定的屬性,然后緊跟一個(gè)要解構(gòu)的變量:

    var robotA = { name: "Bender" };
    var robotB = { name: "Flexo" };
    var { name: nameA } = robotA;
    var { name: nameB } = robotB;
    console.log(nameA);   // => "Bender"
    console.log(nameB);  // => "Flexo"

當(dāng)屬性名與變量名一致時(shí)循未,可以通過(guò)一種實(shí)用的句法簡(jiǎn)寫:

    var { foo, bar } = { foo: "lorem", bar: "ipsum" };
    console.log(foo); // => "lorem" 
    console.log(bar); // => "ipsum"

與數(shù)組解構(gòu)一樣陷猫,你可以隨意嵌套并進(jìn)一步組合對(duì)象解構(gòu):

   var complicatedObj = {
      arrayProp: [
        "Zapp",
        { second: "Brannigan" }
      ]
    };
    var { arrayProp: [first, { second }] } = complicatedObj;
    console.log(first); // => "Zapp"
    console.log(second); // =>  "Brannigan"

當(dāng)你解構(gòu)一個(gè)未定義的屬性時(shí),得到的值為undefined:

    var { missing } = {};
    console.log(missing); // => undefined

請(qǐng)注意只厘,當(dāng)你解構(gòu)對(duì)象并賦值給變量時(shí)烙丛,如果你已經(jīng)聲明或不打算聲明這些變量(即賦值語(yǔ)句前沒(méi)有l(wèi)et、const或var關(guān)鍵字)羔味,你應(yīng)該注意這樣一個(gè)潛在的語(yǔ)法錯(cuò)誤:

{ blowUp } = { blowUp: 10 }; // Syntax error 語(yǔ)法錯(cuò)誤

為什么會(huì)出錯(cuò)河咽?這是因?yàn)镴avaScript語(yǔ)法通知解析引擎將任何以{開始的語(yǔ)句解析為一個(gè)塊語(yǔ)句(例如,{console}是一個(gè)合法塊語(yǔ)句)赋元。解決方案是將整個(gè)表達(dá)式用一對(duì)小括號(hào)包裹:

({ safe } = {});

這樣就沒(méi)有語(yǔ)法錯(cuò)誤了忘蟹;

解構(gòu)值不是對(duì)象、數(shù)組或迭代器

當(dāng)你嘗試解構(gòu)null或undefined時(shí)搁凸,你會(huì)得到一個(gè)類型錯(cuò)誤:

var {blowUp} = null;     // TypeError: null has no properties(null沒(méi)有屬性)

然而媚值,你可以解構(gòu)其它原始類型,例如:布爾值护糖、數(shù)值褥芒、字符串,但是你將得到undefined:

    var {wtf} = NaN;
    console.log(wtf);   // undefined

你可能對(duì)此感到意外,但經(jīng)過(guò)進(jìn)一步審查你就會(huì)發(fā)現(xiàn)锰扶,原因其實(shí)非常簡(jiǎn)單献酗。當(dāng)使用對(duì)象賦值模式時(shí),被解構(gòu)的值[需要被強(qiáng)制轉(zhuǎn)換為對(duì)象坷牛。大多數(shù)類型都可以被轉(zhuǎn)換為對(duì)象罕偎,但nullundefined 卻無(wú)法進(jìn)行轉(zhuǎn)換。當(dāng)使用數(shù)組賦值模式時(shí)京闰,被解構(gòu)的值一定要包含一個(gè)迭代器颜及。

默認(rèn)值

當(dāng)你要解構(gòu)的屬性未定義時(shí)你可以提供一個(gè)默認(rèn)值:

    var [missing = true] = [];
    console.log(missing);  // =>true
    var { message: msg = "Something went wrong" } = {};
    console.log(msg); // => "Something went wrong"
    var { x = 3 } = {};  
    console.log(x); //=> 3
解構(gòu)的實(shí)際應(yīng)用
函數(shù)參數(shù)定義

作為開發(fā)者,我們需要實(shí)現(xiàn)設(shè)計(jì)良好的API蹂楣,通常的做法是為函數(shù)設(shè)計(jì)一個(gè)對(duì)象作為參數(shù)俏站,然后將不同的實(shí)際參數(shù)作為對(duì)象屬性,以避免讓API使用者記住 多個(gè)參數(shù)的使用順序捐迫。我們可以使用解構(gòu)特性來(lái)避免這種問(wèn)題乾翔,當(dāng)我們想要引用它的其中一個(gè)屬性時(shí),大可不必反復(fù)使用這種單一參數(shù)對(duì)象施戴。

function removeBreakpoint({ url, line, column }) {
      // ...
}

這是一段來(lái)自Firefox開發(fā)工具JavaScript調(diào)試器(同樣使用JavaScript實(shí)現(xiàn))的代碼片段,它看起來(lái)非常簡(jiǎn)潔萌丈,我們會(huì)發(fā)現(xiàn)這種代碼模式特別討喜赞哗。

配置對(duì)象參數(shù)

延伸一下之前的示例,我們同樣可以給需要解構(gòu)的對(duì)象屬性賦予默認(rèn)值辆雾。當(dāng)我們構(gòu)造一個(gè)提供配置的對(duì)象肪笋,并且需要這個(gè)對(duì)象的屬性攜帶默認(rèn)值時(shí),解構(gòu)特性就派上用場(chǎng)了度迂。舉個(gè)例子藤乙,jQuery的ajax函數(shù)使用一個(gè)配置對(duì)象作為它的第二參數(shù),我們可以這樣重寫函數(shù)定義:

jQuery.ajax = function (url, {
      async = true,
      beforeSend = noop,
      cache = true,
      complete = noop,
      crossDomain = false,
      global = true,
      // ... 更多配置
    }) {
      // ... do stuff
    };

如此一來(lái)惭墓,我們可以避免對(duì)配置對(duì)象的每個(gè)屬性都重復(fù)var foo = config.foo || theDefaultFoo;這樣的操作(可以設(shè)置默認(rèn)值)坛梁。

與ES6迭代器協(xié)議協(xié)同使用

ECMAScript 6中定義了一個(gè)迭代器協(xié)議,我們?cè)凇?a target="_blank" rel="nofollow">深入淺出ES6(二):迭代器和for-of循環(huán)》中已經(jīng)詳細(xì)解析過(guò)腊凶。當(dāng)你迭代Maps(ES6標(biāo)準(zhǔn)庫(kù)中新加入的一種對(duì)象)后划咐,你可以得到一系列形如[key, value]
的鍵值對(duì),我們可將這些鍵值對(duì)解構(gòu)钧萍,更輕松地訪問(wèn)鍵和值:

var map = new Map();
    map.set(window, "the global");
    map.set(document, "the document");
    for (var [key, value] of map) {
      console.log(key + " is " + value);
    }
    // "[object Window] is the global"
    // "[object HTMLDocument] is the document"

只遍歷鍵:

for (var [key] of map) {
      // ...
}

或只遍歷值:

for (var [,value] of map) {
      // ...
 }
多重返回值

JavaScript語(yǔ)言中尚未整合多重返回值的特性褐缠,但是無(wú)須多此一舉,因?yàn)槟阕约壕涂梢苑祷匾粋€(gè)數(shù)組并將結(jié)果解構(gòu):

    function returnMultipleValues() {
        return [1, 2];
    }
    var [foo, bar] = returnMultipleValues();

或者风瘦,你可以用一個(gè)對(duì)象作為容器并為返回值命名:

  function returnMultipleValues() {
      return {
        foo: 1,
        bar: 2
      };
    }
    var { foo, bar } = returnMultipleValues();

這兩個(gè)模式都比額外保存一個(gè)臨時(shí)變量要好得多队魏。

   function returnMultipleValues() {
      return {
        foo: 1,
        bar: 2
      };
    }
    var temp = returnMultipleValues();
    var foo = temp.foo;
    var bar = temp.bar;

或者使用CPS變換:

function returnMultipleValues(k) {
      k(1, 2);
}
returnMultipleValues((foo, bar) => ...);
使用解構(gòu)導(dǎo)入部分CommonJS模塊

你是否尚未使用ES6模塊?還用著CommonJS的模塊呢吧万搔!沒(méi)問(wèn)題胡桨,當(dāng)我們導(dǎo)入CommonJS模塊X時(shí)官帘,很可能在模塊X中導(dǎo)出了許多你根本沒(méi)打算用的函數(shù)。通過(guò)解構(gòu)登失,你可以顯式定義模塊的一部分來(lái)拆分使用遏佣,同時(shí)還不會(huì)污染你的命名空間:

 const { SourceMapConsumer, SourceNode } = require("source-map");

如果你使用ES6模塊,你一定知道在import聲明中有一個(gè)相似的語(yǔ)法揽浙。

解構(gòu)在許多獨(dú)立小場(chǎng)景中非常實(shí)用状婶。在Mozilla我們已經(jīng)積累了許多有關(guān)解構(gòu)的使用經(jīng)驗(yàn)。十年前馅巷,Lars Hansen在Opera中引入了JS解構(gòu)特性膛虫,Brendan Eich隨后就給Firefox也增加了相應(yīng)的支持,移植時(shí)版本為Firefox 2钓猬。所以我們可以肯定稍刀,漸漸地,你會(huì)在每天使用的語(yǔ)言中加入解構(gòu)這個(gè)新特性敞曹,它可以讓你的代碼變得更加精簡(jiǎn)整潔账月。
本文引自:http://www.infoq.com/cn/articles/es6-in-depth-destructuring/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市澳迫,隨后出現(xiàn)的幾起案子局齿,更是在濱河造成了極大的恐慌,老刑警劉巖橄登,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抓歼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拢锹,警方通過(guò)查閱死者的電腦和手機(jī)谣妻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卒稳,“玉大人蹋半,你說(shuō)我怎么就攤上這事≌箍蓿” “怎么了湃窍?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)匪傍。 經(jīng)常有香客問(wèn)我您市,道長(zhǎng),這世上最難降的妖魔是什么役衡? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任茵休,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘榕莺。我一直安慰自己俐芯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布钉鸯。 她就那樣靜靜地躺著吧史,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唠雕。 梳的紋絲不亂的頭發(fā)上贸营,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音岩睁,去河邊找鬼钞脂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捕儒,可吹牛的內(nèi)容都是我干的冰啃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼刘莹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼阎毅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起点弯,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤净薛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蒲拉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痴腌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年雌团,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片士聪。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锦援,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剥悟,到底是詐尸還是另有隱情灵寺,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布区岗,位于F島的核電站略板,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏慈缔。R本人自食惡果不足惜叮称,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓤檐,春花似錦赂韵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至谴古,卻和暖如春质涛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背讥电。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工蹂窖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恩敌。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓瞬测,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纠炮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子月趟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容