<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 34.解構 > 原文: [http://exploringjs.com/impatient-js/ch_destructuring.html](http://exploringjs.com/impatient-js/ch_destructuring.html) > > 貢獻者:[Kavelaa](https://github.com/Kavelaa) ### 34.1 第一次嘗試解構 通過普通賦值方式,你一次只能獲取數據中的一個元素,例如,通過: ```js const arr = ['a', 'b', 'c']; const x = arr[0]; // 只能獲取第一個 const y = arr[1]; // 只能獲取第二個 ``` 通過解構方式,你可以同時獲取數據中的幾個元素,通過在接收數據的位置進行模式匹配。在上方的代碼的`=`左側就是這樣一個位置。在下方的代碼中,行A中的方括號就是一個解構模式: ```js const arr = ['a', 'b', 'c']; const [x, y] = arr; // (A) assert.equal(x, 'a'); assert.equal(y, 'b'); ``` 這段代碼做了和之前的代碼同樣的事。 注意,這種方式比整個數據要“小巧”:我們只獲取我們需要的數據元素。(譯者注:冒號后面的話才是核心) ### 34.2 構造與提取 為了明白什么是解構,假想JavaScript有兩種截然相反的操作: + 你可以 *構造* 復合數據,例如通過設置屬性和對象文字的方式。 + 你可以從復合數據中 *提取* 數據,例如通過獲取屬性的方式。 構造數據看起來像這樣: ```js // 一次添加一個屬性 const jane1 = {}; jane1.first = 'Jane'; jane1.last = 'Doe'; // 一次添加很多屬性 const jane2 = { first: 'Jane', last: 'Doe', }; assert.deepEqual(jane1, jane2); ``` 提取數據看起來像這樣: ```js const jane = { first: 'Jane', last: 'Doe', }; // 一次獲取一個屬性 const f1 = jane.first; const l1 = jane.last; assert.equal(f1, 'Jane'); assert.equal(l1, 'Doe'); // 一次獲取多個屬性(新方式!) const {first: f2, last: l2} = jane; // (A) assert.equal(f2, 'Jane'); assert.equal(l2, 'Doe'); ``` 行A中的操作方式是全新的:我們聲明兩個變量`f2`和`l2`,并通過 *解構* 方式(多值提取)初始化它們。 下方行A的部分是一個 *解構* 模式: ```js {first: f2, last: l2} ``` 解構模式在語法上類似于用于多值構造的寫法。但是它們出現在接收數據的地方(在賦值語句的左邊),而不是創建數據的地方(在賦值語句的右邊)。 ### 34.3 我們在哪里可以使用解構? 解構模式可用于“數據接收位置”,例如: + 變量聲明: ```js const [a] = ['x']; assert.equal(a, 'x'); let [b] = ['y']; assert.equal(b, 'y'); ``` + 賦值語句: ```js let b; [b] = ['z']; assert.equal(b, 'z'); ``` + 參數定義: ```js const f = ([x]) => x; assert.equal(f(['a']), 'a'); ``` 注意,變量的定義包括在`for-of`循環中的`const`和`let`聲明: ```js const arr = ['a', 'b']; for (const [index, element] of arr.entries()) { console.log(index, element); } // Output: // 0, 'a' // 1, 'b' ``` 在接下來的兩部分中,我們將深入研究兩種類型的解構:對象解構和數組解構。 ### 34.4 對象的解構 *對象解構* 允許您批量提取屬性值,通過看起來像對象寫法的模式: ```js const address = { street: 'Evergreen Terrace', number: '742', city: 'Springfield', state: 'NT', zip: '49007', }; const { street: s, city: c } = address; assert.equal(s, 'Evergreen Terrace'); assert.equal(c, 'Springfield'); ``` 你可以把這種模式想象成一個透明的表格,你把它放在數據上面:模式的鍵`street`在數據中有一個對應的鍵名匹配。因此,數據的值`'Evergreen Terrace'`被賦值給了模式的變量`s`。 你也可以對象解構原始類型的值: ```js const {length: len} = 'abc'; assert.equal(len, 3); ``` 你還可以對象解構數組: ```js const {0:x, 2:y} = ['a', 'b', 'c']; assert.equal(x, 'a'); assert.equal(y, 'c'); ``` 為什么這樣可以?因為[數組索引也是屬性](https://exploringjs.com/impatient-js/ch_arrays.html#array-indices)。 #### 34.4.1 屬性值縮寫 對象寫法支持屬性值縮寫,對象解構模式也支持: ```js const { street, city } = address; assert.equal(street, 'Evergreen Terrace'); assert.equal(city, 'Springfield'); ``` #### 34.4.2 Rest屬性 在對象寫法中,你可以擁有擴展運算符。在對象模式中,可以使用rest屬性(必須放在最后): ```js const obj = { a: 1, b: 2, c: 3 }; const { a: propValue, ...remaining } = obj; // (A) assert.equal(propValue, 1); assert.deepEqual(remaining, {b:2, c:3}); ``` 一個rest參數,例如`remaining`(A行)被賦予一個對象,該對象具有模式中沒有提到鍵的所有數據屬性。 `remaining`也可以看作是從`obj`中非破壞性地刪除屬性`a`的結果。(譯者注:不再需要`a`屬性,但不想改變原對象`obj`,得到一個新的不包含`a`的數組`remaining`) #### 34.4.3 語法陷阱:通過對象解構來賦值 如果我們在賦值過程中使用對象解構,我們就會面臨語法歧義帶來的陷阱——你不能用大括號來開始一個語句,因為JavaScript會認為你在開始一個代碼塊: ```js let prop; assert.throws( () => eval("{prop} = { prop: 'hello' };"), { name: 'SyntaxError', message: 'Unexpected token =', }); ``` > ![](https://raw.githubusercontent.com/apachecn/impatient-js-zh/master/docs/img/6ddc665b06b04cbcdf4bc6a9c514a8c4.svg?sanitize=true) **為什么`eval()`**? > > `eval()`會延遲解析(因此也會延遲`SyntaxError`),直到執行`assert.throw()`的回調。如果我們不使用它,在解析這段代碼時就會得到一個錯誤,`assert.throw()`甚至不會執行。 解決辦法是把整個賦值語句放在括號里: ```js let prop; ({prop} = { prop: 'hello' }); assert.equal(prop, 'hello'); ``` ### 34.5 數組解構 *數組解構* 讓你通過像數組寫法的方式,批量提取數組元素: ```js const [x, y] = ['a', 'b']; assert.equal(x, 'a'); assert.equal(y, 'b'); ``` 在數組的模式中,你可以通過提交空值的方式來跳過元素: ```js const [, x, y] = ['a', 'b', 'c']; // (A) assert.equal(x, 'b'); assert.equal(y, 'c'); ``` 在A行,數組模式的第一個元素為空,這就是索引為0的數組元素被忽略的原因。 #### 34.5.1 數組解構可以用于任何可遍歷的數據結構 數組解構可以用于任何可遍歷的值,而不僅僅是數組: ```js // Sets數據結構是iterable的 const mySet = new Set().add('a').add('b').add('c'); const [first, second] = mySet; assert.equal(first, 'a'); assert.equal(second, 'b'); // 字符串數據結構是iterable的 const [a, b] = 'xyz'; assert.equal(a, 'x'); assert.equal(b, 'y'); ``` #### 34.5.2 Rest參數 在數組文字中,你可以使用擴展運算符。在數組模式中,你可以使用rest參數(必須放在最后): ```js const [x, y, ...remaining] = ['a', 'b', 'c', 'd']; // (A) assert.equal(x, 'a'); assert.equal(y, 'b'); assert.deepEqual(remaining, ['c', 'd']); ``` rest元素變量,例如`remaining`(A行)被賦予一個數組,其中包含尚未提到的已解構值的所有元素。 ### 34.6 解構的一些例子 #### 34.6.1 數組解構:交換變量的值 你可以使用數組解構來交換兩個變量的值,而不需要臨時變量: ```js let x = 'a'; let y = 'b'; [x,y] = [y,x]; // swap assert.equal(x, 'b'); assert.equal(y, 'a'); ``` #### 34.6.2 數組解構:用于會返回數組的操作 數組解構在用于會返回數組的操作時非常有用。例如,正則表達式方法`.exec()`: ```js // Skip the element at index 0 (the whole match): const [, year, month, day] = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ .exec('2999-12-31'); assert.equal(year, '2999'); assert.equal(month, '12'); assert.equal(day, '31'); ``` #### 34.6.3 對象解構:多個返回值 解構對函數返回多個值的情況非常有用——要么打包為數組,要么打包為對象。 假想一個函數`findElement()`,用于尋找一個數組內的元素: ```js findElement(array, (value, index) => ?boolean expression?) ``` 它的第二個參數是一個函數,該函數接收元素的值和索引,并返回一個布爾值,指示這是否是調用者正在尋找的元素。 我們現在面臨一個難題:`findElement()`應該返回它找到的元素的值還是索引的值?一個解決方案是創建兩個單獨的函數,但這會導致代碼重復,因為這兩個函數非常相似。 下面的實現通過返回一個同時包含找到的元素的索引和值的對象,來避免重復: ```js function findElement(arr, predicate) { for (let index=0; index < arr.length; index++) { const value = arr[index]; if (predicate(value)) { // 有所發現的話 return { value, index }; } } // 什么都沒找到的話 return { value: undefined, index: -1 }; } ``` 解構幫助我們處理`findElement()`的結果: ```js const arr = [7, 8, 6]; const {value, index} = findElement(arr, x => x % 2 === 0); assert.equal(value, 8); assert.equal(index, 1); ``` 當我們使用屬性的鍵名時,我們聲明值和索引時的順序并不重要: ```js const {index, value} = findElement(arr, x => x % 2 === 0); ``` 更妙的是,如果我們只對以下兩種結果中的一種感興趣,解構也能很好地幫助我們: ```js const arr = [7, 8, 6]; const {value} = findElement(arr, x => x % 2 === 0); assert.equal(value, 8); const {index} = findElement(arr, x => x % 2 === 0); assert.equal(index, 1); ``` 這些方便結合在一起,使得這種處理多個返回值的方法非常通用。 ### 34.7 如果一個模式的一部分不匹配,會發生什么? 如果一個模式的一部分不匹配,會發生什么?如果使用非批處理操作符也會發生同樣的事情:您將得到`undefined`的結果。 #### 34.7.1 對象解構時缺少屬性 如果對象模式中的屬性在右側沒有匹配項,則得到`undefined`: ```js const {prop: p} = {}; assert.equal(p, undefined); ``` #### 34.7.2 數組解構時缺少元素 如果數組模式中的元素在右側沒有匹配項,則得到`undefined`: ```js const [x] = []; assert.equal(x, undefined); ``` ### 34.8 什么值無法被解構? #### 34.8.1 你不能對`undefined`和`null`使用對象解構 只有當要解構的值未定義(`undefined`)或為空(`null`)時,對象解構才會失敗。也就是說,當通過點操作符訪問屬性時也會失敗。 ```js assert.throws( () => { const {prop} = undefined; }, { name: 'TypeError', message: "Cannot destructure property `prop` of " + "'undefined' or 'null'.", } ); assert.throws( () => { const {prop} = null; }, { name: 'TypeError', message: "Cannot destructure property `prop` of " + "'undefined' or 'null'.", } ); ``` #### 34.8.2 你不能對無法遍歷的值進行數組解構 數組解構要求解構值是可遍歷的。因此,不能對未定義(`undefined`)或者空(`null`)的數組進行解構,同樣你也不能解構無法遍歷的對象: ```js assert.throws( () => { const [x] = {}; }, { name: 'TypeError', message: '{} is not iterable', } ); ``` > ![](https://raw.githubusercontent.com/apachecn/impatient-js-zh/master/docs/img/bf533f04c482f83bfc407f318306f995.svg?sanitize=true) **測試:基本** > > 請看 [quiz app](https://exploringjs.com/impatient-js/ch_quizzes-exercises.html#quizzes) ### 34.9 (高級用法) 余下部分皆為高級用法。 ### 34.10 默認值 一般情況下,如果一個模式沒有匹配,則將對應的變量設置為`undefined`: ```js const {prop: p} = {}; assert.equal(p, undefined); ``` 如果你想要設定一個同樣用途的不同的值,你需要指定一個初始值(通過`=`): ```js const {prop: p = 123} = {}; // (A) assert.equal(p, 123); ``` 在行A中,我們指定`p`的默認值為`123`。該默認值會生效,因為要解構的的數據中沒有名為`prop`的屬性。 #### 34.10.1 默認值在數組解構中的用法 在這里,我們有兩個默認值被賦給變量`x`和`y`,因為被解構的數組中不存在相應的元素。 ```js const [x=1, y=2] = []; assert.equal(x, 1); assert.equal(y, 2); ``` 給數組模式的第一個元素的默認值是`1`,給第二個元素的值是`2`。 #### 34.10.2 默認值對象解構中的用法 你也可以為對象解構指定默認值: ```js const {first: f='', last: l=''} = {}; assert.equal(f, ''); assert.equal(l, ''); ``` 屬性鍵`first`和屬性鍵`last`都不存在于被解構的對象中。因此,默認值會生效。 使用屬性值縮寫,代碼會變得更簡單: ```js const {first='', last=''} = {}; assert.equal(first, ''); assert.equal(last, ''); ``` ### 34.11 參數定義和解構的相似性 考慮到我們在本章所學到的內容,參數定義與數組模式(rest元素、默認值等)有很多共同點。事實上,以下兩個函數聲明是等價的: ```js function f1(?pattern1?, ?pattern2?) { // ··· } function f2(...args) { const [?pattern1?, ?pattern2?] = args; // ··· } ``` ### 34.12 嵌套解構 到目前為止,我們只在解構模式中使用變量作為 *賦值目標* (數據接收方)。但是你也可以使用模式作為賦值目標,這使你能夠將模式嵌套到任意深度: ```js const arr = [ { first: 'Jane', last: 'Bond' }, { first: 'Lars', last: 'Croft' }, ]; const [, {first}] = arr; //(A) assert.equal(first, 'Lars'); ``` 在A行的數組模式中,有一個數組嵌套,位于索引1。(譯者注:即`{first}`,實際上作者并沒有注釋A行在何處,是我后來添加上去的。或許作者是故意的呢?哈哈。) 嵌套模式不太容易理解,所以最好適當地使用。 > ![](https://raw.githubusercontent.com/apachecn/impatient-js-zh/master/docs/img/bf533f04c482f83bfc407f318306f995.svg?sanitize=true) **測試:高級用法** > > 請看[quiz app](https://exploringjs.com/impatient-js/ch_quizzes-exercises.html#quizzes)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看