ES6解構賦值詳解

来源:http://www.cnblogs.com/dakang233/archive/2017/05/21/6885117.html
-Advertisement-
Play Games

解構賦值(destructuring assignment)語法是一個 Javascript 表達式,這種語法能夠更方便的提取出 Object 或者 Array 中的數據。這種語法可以在接受提取的數據的地方使用,比如一個表達式的左邊。有明確的語法模式來告訴我們如何使用這種語法提取需要的數據值。 ...


文章轉載自:http://www.zhufengpeixun.cn/article/167

解構賦值(destructuring assignment)語法是一個 Javascript 表達式,這種語法能夠更方便的提取出 Object 或者 Array 中的數據。這種語法可以在接受提取的數據的地方使用,比如一個表達式的左邊。有明確的語法模式來告訴我們如何使用這種語法提取需要的數據值。

Object 的解構

解構 Object:

const obj = { first: 'Jane', last: 'Doe' };
const {first: f, last: l} = obj;
// f = 'Jane'; l = 'Doe'

// {prop} is short for {prop: prop}
const {first, last} = obj;
// first = 'Jane'; last = 'Doe'

解構能幫助更好地處理方法返回的對象:

const obj = { foo: 123 };

const {writable, configurable} = Object.getOwnPropertyDescriptor(obj, 'foo');

console.log(writable, configurable); // true true

Array 的解構

解構數組,對所有可遍歷的值有效。

let foo = ["one", "two", "three"];

let [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"

const iterable = ['a', 'b'];
const [x, y] = iterable;
// x = 'a'; y = 'b'

[x, y] = iterable;

// window.x = 'a'; window.y = 'b';

同樣的,解構數組也能幫助我們更好地處理函數返回值:

const [all, year, month, day] =
    /^(\d\d\d\d)-(\d\d)-(\d\d)$/
    .exec('2999-12-31');

而且,你也可以忽略你不感興趣的返回值:

function f() {
  return [1, 2, 3];
}

let [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

你也可以忽略全部返回值,不過似乎沒啥用:

[,,] = f();

當解構一個數組時,可以使用剩餘模式(拓展語句,Spread operator),將數組剩餘部分賦值給一個變數。

let [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]

在什麼地方可以使用解構

解構可以在下麵這些情景中使用,只展現了數組模式的演示,對象模式也是如此。

// 變數聲明:
const [x] = ['a'];
let [x] = ['a'];
var [x] = ['a'];

// 賦值: 下麵這種情況將會在全局變數上添加一個 x 屬性,值為‘a‘
[x] = ['a']; 

// 參數的定義:
function userId({id}) {
  return id;
}

function whois({displayName: displayName, fullName: {firstName: name}}){
  console.log(displayName + "is" + name);
}

var user = { 
  id: 42, 
  displayName: "jdoe",
  fullName: { 
      firstName: "John",
      lastName: "Doe"
  }
};

console.log("userId:" + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"

function f([x]) { ··· }
f(['a']);

也可以在 for-of 迴圈中使用:

const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
    console.log(index, element);
}
// Output:
// 0 a
// 1 b

解構賦值的模型 patterns

在解構中,有下麵兩部分參與:

  • Destructuring source: 解構的源,將要被解構的數據,比如解構賦值表達式的右邊部分。
  • Destructuring target: 解構的目標,比如解構複製表達式的左邊部分。

解構的目標可以是下麵三個的任意一個:

  • 賦值對象,Assigment Patterns。例如 x . 賦值對象通常來說是一個變數。但是在解構賦值中,你有更多的選擇,稍後會講到。
  • 對象模型,Object Patterns。比如:{first: «pattern», last: «pattern»}
  • 數組模型,Object Patterns。比如:[«pattern», «pattern»]

可以任意嵌套模型,而且是可以非常任性的嵌套。

const obj = { a: [{ foo: 123, bar: 'abc' }, {}], b: true };
const { a: [{foo: f}] } = obj; // f = 123

解構的 patterns 如何訪問到值的內部結構?

在一個表達式 pattern = someValue 中,pattern是如何訪問 someValue 的呢?

Object patterns 將 value 轉換成 Object

在訪問屬性之前,object pattern 將解構的源數據(destructuing source)轉換成對象。

const {length : len} = ‘abc’; // len = 3 
const {toString: s} = 123; // s = Number.prototype.toString

使用“對象解構”的缺點

在這個過程中,強制轉換成對象的過程不是通過 Object() 方法,而是通過內置的操作方法 toObject()。這兩個操作處理undefined 和null的方式不太一樣。

Object()方法將原始類型值轉換成包裝類型對象(wrapper object),原來的值原封不動。

> typeof Object('abc')
'object'

> var obj = {};
> Object(obj) === obj
true

也會將undefined 和 null 轉換成一個空的對象。

> Object(undefined)
{}
> Object(null)
{}

對比之下,當遇到 undefined 和null的時候,toObject()方法則會拋出一個錯誤。所以下麵的解構是失敗的:

const { prop: x } = undefined; // TypeError
const { prop: y } = null; // TypeError

因此,你可以使用空對象模型 {} 來檢查一個值是否被強制轉換成了一個對象。正如前面提到的規則,undefined和 null 將會拋出錯誤

({} = [true, false]); // OK, Arrays are coercible to objects
({} = 'abc'); // OK, strings are coercible to objects

({} = undefined); // TypeError
({} = null); // TypeError

表達式兩邊的括弧是必須的,因為在 JavaScript 中,聲明不能以花括弧開始。

在可遍歷的量中使用數組模型

數組解構使用一個迭代器來獲取數據源中的元素。因此,你可以對任何可以遍歷的值使用數組解構。

字元串是可遍歷的:

const [x, ...y] = 'abc'; // x='a'; y=['b', 'c']

我們無法通過索引訪問 Set 中的元素,但是可以通過迭代器。所以,數組解構能夠在 Sets 上工作:

const [x,y] = new Set(['a', 'b']); // x='a'; y='b’;

Set的迭代器總是按照元素插入的順序將元素返回,所以上述的解構返回的結果總是相同的。

使用“數組解構”的缺點

如果一個值有一個 key 為 Symbol.iterator 的方法,這個方法返回的是一個對象,那麼這個值是可以遍歷的。如果被解構的值不能遍歷的,那麼“數組解構”會拋出一個 TypeError 錯誤。

let x;
[x] = [true, false]; // OK, Arrays are iterable
[x] = 'abc'; // OK, strings are iterable
[x] = { * [Symbol.iterator]() { yield 1 } }; // OK, iterable

[x] = {}; // TypeError, empty objects are not iterable
[x] = undefined; // TypeError, not iterable
[x] = null; // TypeError, not iterable

可以用一個空的數組模型 [] 來檢查值是不是可遍歷的:

[] = {}; // TypeError, empty objects are not iterable
[] = undefined; // TypeError, not iterable
[] = null; // TypeError, not iterable

預設值

預設值是可選的,在數據源中找不到對應的值時,如果設置了預設值,則匹配這個預設值作為匹配結果,否則返回 undefined。

const [x=3, y] = []; // x = 3; y = undefined。
const {foo: x=3, bar: y} = {}; // x = 3; y = undefined

undefined 也會觸發預設值

當解構模式有匹配結果,且匹配結果是 undefined 時,也會使用預設值作為返回結果:

const [x=1] = [undefined]; // x = 1
const {prop: y=2} = {prop: undefined}; // y = 2

預設值是根據需要計算出來的

也就是說下麵的解構:

const {prop: y=someFunc()} = someValue;

相當於:

let y;
if (someValue.prop === undefined) {
    y = someFunc();
} else {
    y = someValue.prop;
}

使用 console.log() 可以觀察到:

> function log(x) { console.log(x); return 'YES' }
> const [a=log('hello')] = [];
> a
'YES'
> const [b=log('hello')] = [123];
> b
123

在第二個解構中,預設值沒有觸發,並且 log() 沒有被調用。

預設值可以引用模式中的其他變數

預設值可以引用模式中的任何變數,包括相同模式中的其他變數:

const [x=3, y=x] = [];     // x=3; y=3
const [x=3, y=x] = [7];    // x=7; y=7
const [x=3, y=x] = [7, 2]; // x=7; y=2

但是,變數的順序很關鍵,從左到右,先聲明的變數不能引用後聲明的變數,也就是左邊的不能引用右邊的。

const [x=y, y=3] = []; // ReferenceError

patterns 的預設值

到目前為止,我們所看到的都是模式中變數的預設值,我們也可以為模式設置預設值。

const [{prop: x} = {}] = [];

如果整個模式沒有匹配結果,則使用 {} 作為數據源來匹配。

const { prop: x } = {}; // x = undefined

上面的例子中,x 為 undefined 可能還是不夠直觀。看下麵這個例子:

const [{prop: x} = {props: 'abc'}] = []; // x=abc

對象解構的更多特性

屬性,屬性值的簡寫

如果屬性值是一個變數,和屬性的 key 相同,就可以忽略這個 key:

const { x, y } = { x: 11, y: 8 }; // x = 11; y = 8


// 等價於
const { x: x, y: y } = { x: 11, y: 8 };

計算後的屬性的鍵

如果把表達式放入方括弧中,可以用這個表達式聲明屬性的鍵:

const FOO = 'foo';
const { [FOO]: f} = {fooL 123}; // f = 123
這也使得可以使用 symbols 來做屬性的鍵:

// Create and destructure a property whose key is a symbol
const KEY = Symbol();
const obj = { [KEY]: 'abc' };
const { [KEY]: x } = obj; // x = 'abc'

// Extract Array.prototype[Symbol.iterator]
const { [Symbol.iterator]: func } = [];
console.log(typeof func); // function

數組解構的更多特性

在解構的過程中可以跳過一些元素:

const [,,x,y] = [1,2,3,4]; // x= 3 y = 4;

剩餘運算符 Rest operator (…)

剩餘運算符可以將一個可遍歷對象中剩餘的元素提取到一個數組中。如果這個運算符在數組模式中使用,運算符必須放在最後:

const [x, ...y] = [1,2,3,4]; // x=1; y=[2,3,4];

要註意的時,拓展運算符(spread operator)與剩餘操作符有著相同的語法 - 三個點。但是它們之間有區別:前者將數組變成多個元素;後者則用來解構和提取數據,多個元素壓縮成一個元素。

如果運算符找不到任何元素,將會匹配一個空的數組,永遠不會返回 undefined 或者 null。例如:

const [x, y, ...z] = ['a']; // x='a'; y=undefined; z

操作符不一定非要是一個變數,也可以使用模式:

const [x, ...[y, z]] = ['a', 'b', 'c']; // x = 'a'; y = 'b'; z = 'c'

解構的陷阱

在使用解構的時候,有兩點要考慮清楚:

不能使用大括弧作為聲明語句的開頭;
在解構的過程中,可以申明變數或者分配給變數,但是不能同時這麼做;

解構的幾個例子

在 for-of 中使用解構:

const map = new Map().set(false, 'no').set(true, 'yes');
for (const [key, value] of map) {
  console.log(key + 'is' + value);
}

使用解構交換兩個變數的值:

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

或者:

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

還可以分割數據:

const [first, ...rest] = ['a', 'b', 'c']; // first = 'a'; rest = ['b', 'c']

處理方法返回的數組更加方便:

const [all, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec('2999-12-31');

const cells = 'Jane\tDoe\tCTO'
const [firstName, lastName, title] = cells.split('\t');
console.log(firstName, lastName, title);

要註意的一點是:exec 等一些方法可能會返回 null,導致程式拋出錯誤TypeError,此時需要添加一個預設值:

const [, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec(someStr) || [];

文章轉載自:http://www.zhufengpeixun.cn/article/167


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上一篇介紹了模板引擎pug.js的用法,這一篇就主要寫後臺邏輯了。 後臺的大部分的功能都有了,只是在已經登錄的狀態下,前臺和後臺的邏輯處理還不是很完善。 先上幾張圖吧,仿舊版的簡書,改了下UI,因為沒有簡書那麼多內容,所以沒必要完全做成一樣的。 1.項目結構 app.js 是整個工程的入口 mode ...
  • 此文章主要總結UIEvent相關的事件,如有不對的地方,歡迎指正。 一、uitls.js(綁定事件公共類) 主要做一些事件名的相容性處理。 二、baseEvent 2.1 相容點 2.2 一些代碼 三、焦點事件 不是所有的標簽都支持焦點事件,如div(不可編輯狀態)、span、p等這類佈局和顯示內容 ...
  • 一、顏色值 1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>顏色值</title> 6 <style type="text/css"> 7 8 </style> 9 </head> 10 11 <body> ...
  • 閉包: 有權訪問另一個函數作用域中變數的函數 用處: 1 讀取函數內部的變數 2 讓某些變數的值始終保持在記憶體中 在瞭解閉包之前,我們需要明白變數的作用域,即函數內部能夠讀取全局變數,但是函數外卻不能讀取函數內的局部變數 1 當使用閉包訪問局部變數 此時f2就是閉包 2 累加 2.1 使用全局變數累 ...
  • 使用top和left屬性可能會造成元素相互重疊在一起,此時可以使用z-index屬性。z-index屬性用來控制重疊元素的顯示順序,值較高的元素將覆蓋值較低的元素。如果使用值-1,則表示元素將至於頁面預設文本的後面,這對於設置背景圖案是很有用的。如果把電腦屏幕看作X-Y平面的話,那麼z軸就是垂直於屏 ...
  • 本文轉載自:http://www.cnblogs.com/lovesong/p/5745893.html meta標簽作用 META標簽是HTML標記HEAD區的一個關鍵標簽,提供文檔字元集、使用語言、作者等基本信息,以及對關鍵詞和網頁等級的設定等,最大的作用是能夠做搜索引擎優化(SEO)。 PS: ...
  • 1.<label hidden>看得見嗎</label> //hidden為隱藏屬性 2. <input tabindex="1" /> <textarea tabindex="2" spellcheck="true" cols="60" rows="5"></textarea> //spellch ...
  • 盒子陰影樣式單詞:box-shadow 語法 <style> div{box-shadow:0 0 1px #000 inset;} </style> 其中,第一個和第二個0分別代表邊框間距靠左和靠上;1px表示陰影範圍;#000表示陰影顏色為黑色;inset 代表框內陰影 ,沒有inset 則代表 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...