ES6經常使用語法

變量的解構賦值

1. 數組的解構賦值

ES6容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。
之前,爲變量賦值,只能直接指定值。ajax

案例
var a = 1;   
    var b = 2;    
    var c = 3;    
    //ES6容許寫成下面這樣。   
    var [a, b, c] = [1, 2, 3];

2. 對象的解構賦值

解構不只能夠用於數組,還能夠用於對象。json

var { foo, bar } = { foo: "aaa", bar: "bbb" };    
    foo // "aaa"   
    bar // "bbb"
注意: 對象的解構與數組有一個重要的不一樣。
  • 數組的元素是按次序排列的,變量的取值由它的位置決定;
  • 對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
案例
var { bar, foo } = { foo: "aaa", bar: "bbb" };   
    foo // "aaa"   
    bar // "bbb"   
    var { baz } = { foo: "aaa", bar: "bbb" };    
    baz // undefined

上面代碼的第一個例子,等號左邊的兩個變量的次序,與等號右邊兩個同名屬性的次序不一致,可是對取值徹底沒有影響。第二個例子的變量沒有對應的同名屬性,致使取不到值,最後等於undefined。 若是變量名與屬性名不一致,必須寫成下面這樣。數組

var { foo: baz } = { foo: 'aaa', bar: 'bbb' };   
    baz // "aaa"   
    let obj = { first: 'hello', last: 'world' };   
    let { first: f, last: l } = obj;   
    f // 'hello'   
    l // 'world'

這實際上說明,對象的解構賦值是下面形式的簡寫(參見《對象的擴展》一章)。瀏覽器

var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

也就是說,對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。
真正被賦值的是後者,而不是前者。數據結構

var { foo: baz } = { foo: "aaa", bar: "bbb" };
    baz // "aaa"
    foo // error: foo is not defined

上面代碼中,真正被賦值的是變量baz,而不是模式foo。
注意: 採用這種寫法時,變量的聲明和賦值是一體的。
對於let和const來講,變量不能從新聲明,因此一旦賦值的變量之前聲明過,就會報錯。async

let foo;
    let {foo} = {foo: 1}; // SyntaxError: Duplicate declaration "foo"
    let baz;
    let {bar: baz} = {bar: 1}; // SyntaxError: Duplicate declaration "baz"

上面代碼中,解構賦值的變量都會從新聲明,因此報錯了。
不過,由於var命令容許從新聲明,因此這個錯誤只會在使用let和const命令時出現。
若是沒有第二個let命令,上面的代碼就不會報錯。函數

3. 用途

變量的解構賦值用途不少。ui

  • 交換變量的值
[x, y] = [y, x];

上面代碼交換變量x和y的值,這樣的寫法不只簡潔,並且易讀,語義很是清晰。this

  • 從函數返回多個值

函數只能返回一個值,若是要返回多個值,只能將它們放在數組或對象裏返回。有了解構賦值,取出這些值就很是方便。url

// 返回一個數組接收值
function example() {
    return [1, 2, 3];
}
var [a, b, c] = example();


// 返回一個對象接收值
function example() {
    return {foo: 1, bar: 2};
}

var { foo, bar } = example();
  • 函數參數的定義

解構賦值能夠方便地將一組參數與變量名對應起來。

// 參數是一組有次序的值
function f([x, y, z]) { ... }

f([1, 2, 3]);



// 參數是一組無次序的值
function f({x, y, z}) { ... }

f({z: 3, y: 2, x: 1});
  • 提取JSON數據

解構賦值對提取JSON對象中的數據,尤爲有用。

var jsonData = {
    id: 42,
    status: "OK",
    data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]
  • 函數參數的默認值
jQuery.ajax = function (url, {
       async = true,
       beforeSend = function () {},
       cache = true,
       complete = function () {},
       crossDomain = false,
       global = true,
       // ... more config
   }) {
   // ... do stuff
   };

指定參數的默認值,就避免了在函數體內部再寫var foo = config.foo || 'default foo';這樣的語句。

  • 遍歷Map結構

任何部署了Iterator接口的對象,均可以用for...of循環遍歷。Map結構原生支持Iterator接口,配合變量的解構賦值,獲取鍵名和鍵值就很是方便。

var map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');
    
    for (let [key, value] of map) {
        console.log(key + " is " + value);
    }
    // first is hello
    // second is world
    
    
    //若是隻想獲取鍵名,或者只想獲取鍵值,能夠寫成下面這樣。
    // 獲取鍵名
    for (let [key] of map) {
        // ...
    }
    
    // 獲取鍵值
    for (let [,value] of map) {
        // ...
    }
  • 輸入模塊的指定方法

加載模塊時,每每須要指定輸入那些方法。解構賦值使得輸入語句很是清晰。

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

2. includes(), startsWith(), endsWith()

傳統上,JavaScript只有indexOf方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。
ES6又提供了三種新方法。

  • includes():返回布爾值,表示是否找到了參數字符串。
  • startsWith():返回布爾值,表示參數字符串是否在源字符串的頭部。
  • endsWith():返回布爾值,表示參數字符串是否在源字符串的尾部。
var s = 'Hello world!';    
s.startsWith('Hello') // true    
s.endsWith('!') // true    
s.includes('o') // true

這三個方法都支持第二個參數,表示開始搜索的位置。

var s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

上面代碼表示,使用第二個參數n時,endsWith的行爲與其餘兩個方法有所不一樣。
它針對前n個字符,而其餘兩個方法針對從第n個位置直到字符串結束。

3. repeat()

repeat方法返回一個新字符串,表示將原字符串重複n次。

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

參數若是是小數,會被取整。

'na'.repeat(2.9) // "nana"

若是repeat的參數是負數或者Infinity,會報錯。

'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError

特殊狀況: 若是參數是0到-1之間的小數,則等同於0,這是由於會先進行取整運算。
0到-1之間的小數,取整之後等於-0,repeat視同爲0。

'na'.repeat(-0.9) // ""

 //參數NaN等同於0。
'na'.repeat(NaN) // ""

若是repeat的參數是字符串,則會先轉換成數字。
'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"

4.字符串補全 padStart(),padEnd()

ES7推出了字符串補全長度的功能。若是某個字符串不夠指定長度,會在頭部或尾部補全。
padStart用於頭部補全,padEnd用於尾部補全。

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

上面代碼中,padStart和padEnd一共接受兩個參數

  • 第一個參數用來指定字符串的最小長度
  • 第二個參數是用來補全的字符串
說明
  1. 若是原字符串的長度,等於或大於指定的最小長度,則返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
  1. 若是用來補全的字符串與原字符串,二者的長度之和超過了指定的最小長度,則會截去超出位數的補全字符串。
'abc'.padStart(10, '0123456789')  // '0123456abc'
  1. 若是省略第二個參數,則會用空格補全長度。
'x'.padStart(4)   // ' x'
'x'.padEnd(4)     // 'x '
  1. padStart的常見用途是爲數值補全指定位數。下面代碼生成10位的數值字符串。
'1'.padStart(10, '0')       // "0000000001"
'12'.padStart(10, '0')      // "0000000012"
'123456'.padStart(10, '0')  // "0000123456"
  1. 另外一個用途是提示字符串格式。
'12'.padStart(10, 'YYYY-MM-DD')     // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD')  // "YYYY-09-12"

5. Array.from()

Array.from方法用於將兩類對象轉爲真正的數組:

  • 相似數組的對象(array-like object > 參數列表: arguments ; document獲取到的節點)
  • 可遍歷(iterable)的對象(包括ES6新增的數據結構Set和Map)。

下面是一個相似數組的對象,Array.from將它轉爲真正的數組。

let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
};

// ES5的寫法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的寫法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

實際應用中,常見的相似數組的對象是DOM操做返回的NodeList集合,以及函數內部的arguments對象。
Array.from均可以將它們轉爲真正的數組。

// NodeList對象
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) {
    console.log(p);
});

// arguments對象
function foo() {
    var args = Array.from(arguments);
// ...
}

上面代碼中,querySelectorAll方法返回的是一個相似數組的對象,只有將這個對象轉爲真正的數組,才能使用forEach方法。
只要是部署了Iterator接口的數據結構,Array.from都能將其轉爲數組。

Array.from('hello')
    // ['h', 'e', 'l', 'l', 'o']
    let namesSet = new Set(['a', 'b'])
    Array.from(namesSet) // ['a', 'b']
    
    //上面代碼中,字符串和Set結構都具備Iterator接口,所以能夠被Array.from轉爲真正的數組。
    //若是參數是一個真正的數組,Array.from會返回一個如出一轍的新數組。
    
    Array.from([1, 2, 3])
    // [1, 2, 3] 
    //值得提醒的是,擴展運算符(...)也能夠將某些數據結構轉爲數組。
    
    
    //arguments對象
    function foo() {
        var args = [...arguments];
    }
    
    // NodeList對象
    [...document.querySelectorAll('div')]

擴展運算符背後調用的是遍歷器接口(Symbol.iterator),若是一個對象沒有部署這個接口,就沒法轉換。
Array.from方法則是還支持相似數組的對象。所謂相似數組的對象,本質特徵只有一點,即必須有length屬性。
所以,任何有length屬性的對象,均可以經過Array.from方法轉爲數組,而此時擴展運算符就沒法轉換。

Array.from({ length: 3 });
// [ undefined, undefined, undefined ]

上面代碼中,Array.from返回了一個具備三個成員的數組,每一個位置的值都是undefined。擴展運算符轉換不了這個對象。對於尚未部署該方法的瀏覽器,能夠用Array.prototype.slice方法替代。

const toArray = (() =>
Array.from ? Array.from : obj => [].slice.call(obj)
)();

Array.from還能夠接受第二個參數,做用相似於數組的map方法,用來對每一個元素進行處理,將處理後的值放入返回的數組。

Array.from(arrayLike, x => x * x);

// 等同於
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x)

// [1, 4, 9]
//下面的例子是取出一組DOM節點的文本內容。
let spans = document.querySelectorAll('span.name');

// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);

// Array.from()
let names2 = Array.from(spans, s => s.textContent)

//下面的例子將數組中布爾值爲false的成員轉爲0。
Array.from([1, , 2, , 3], (n) => n || 0)
// [1, 0, 2, 0, 3]

//另外一個例子是返回各類數據的類型。
function typesOf () {
    return Array.from(arguments, value => typeof value)
}\
typesOf(null, [], NaN)
// ['object', 'object', 'number']

若是map函數裏面用到了this關鍵字,還能夠傳入Array.from的第三個參數,用來綁定this。
Array.from()能夠將各類值轉爲真正的數組,而且還提供map功能。
這實際上意味着,只要有一個原始的數據結構,你就能夠先對它的值進行處理,而後轉成規範的數組結構,進而就可使用數量衆多的數組方法。

Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']

上面代碼中,Array.from的第一個參數指定了第二個參數運行的次數。
這種特性可讓該方法的用法變得很是靈活。

Array.from()的另外一個應用是,將字符串轉爲數組,而後返回字符串的長度。
由於它能正確處理各類Unicode字符,能夠避免JavaScript將大於\uFFFF的Unicode字符,算做兩個字符的bug。

function countSymbols(string) {
    return Array.from(string).length;
}
相關文章
相關標籤/搜索