ES6容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。
之前,爲變量賦值,只能直接指定值。ajax
var a = 1; var b = 2; var c = 3; //ES6容許寫成下面這樣。 var [a, b, c] = [1, 2, 3];
解構不只能夠用於數組,還能夠用於對象。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命令,上面的代碼就不會報錯。函數
變量的解構賦值用途不少。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對象中的數據,尤爲有用。
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';這樣的語句。
任何部署了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");
傳統上,JavaScript只有indexOf方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。
ES6又提供了三種新方法。
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個位置直到字符串結束。
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"
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一共接受兩個參數
- 第一個參數用來指定字符串的最小長度
- 第二個參數是用來補全的字符串
'xxx'.padStart(2, 'ab') // 'xxx' 'xxx'.padEnd(2, 'ab') // 'xxx'
'abc'.padStart(10, '0123456789') // '0123456abc'
'x'.padStart(4) // ' x' 'x'.padEnd(4) // 'x '
'1'.padStart(10, '0') // "0000000001" '12'.padStart(10, '0') // "0000000012" '123456'.padStart(10, '0') // "0000123456"
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12" '09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
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; }