對象的擴展運算符
理解對象的擴展運算符其實很簡單,只要記住一句話就能夠:javascript
對象中的擴展運算符(...)用於取出參數對象中的全部可遍歷屬性,拷貝到當前對象之中java
let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }
上述方法實際上等價於:redux
let bar = { a: 1, b: 2 };
let baz = Object.assign({}, bar); // { a: 1, b: 2 }
Object.assign方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target)。數組
Object.assign方法的第一個參數是目標對象,後面的參數都是源對象。(若是目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性)。數據結構
一樣,若是用戶自定義的屬性,放在擴展運算符後面,則擴展運算符內部的同名屬性會被覆蓋掉。函數
let bar = {a: 1, b: 2};
let baz = {...bar, ...{a:2, b: 4}}; // {a: 2, b: 4}
利用上述特性就能夠很方便的修改對象的部分屬性。在redux中的reducer函數規定必須是一個純函數(若是不是很清楚什麼是純函數的能夠參考這裏),reducer中的state對象要求不能直接修改,能夠經過擴展運算符把修改路徑的對象都複製一遍,而後產生一個新的對象返回。es5
這裏有點須要注意的是擴展運算符對對象實例的拷貝屬於一種淺拷貝。確定有人要問什麼是淺拷貝?咱們知道javascript中有兩種數據類型,分別是基礎數據類型和引用數據類型。基礎數據類型是按值訪問的,常見的基礎數據類型有Number、String、Boolean、Null、Undefined,這類變量的拷貝的時候會完整的複製一份;引用數據類型好比Array,在拷貝的時候拷貝的是對象的引用,當原對象發生變化的時候,拷貝對象也跟着變化,好比:spa
let obj1 = { a: 1, b: 2};
let obj2 = { ...obj1, b: '2-edited'};
console.log(obj1); // {a: 1, b: 2}
console.log(obj2); // {a: 1, b: "2-edited"}
上面這個例子擴展運算符拷貝的對象是基礎數據類型,所以對obj2的修改並不會影響obj1,若是改爲這樣:prototype
let obj1 = { a: 1, b: 2, c: {nickName: 'd'}};
let obj2 = { ...obj1};
obj2.c.nickName = 'd-edited';
console.log(obj1); // {a: 1, b: 2, c: {nickName: 'd-edited'}}
console.log(obj2); // {a: 1, b: 2, c: {nickName: 'd-edited'}}
這裏能夠看到,對obj2的修改影響到了被拷貝對象obj1,緣由上面已經說了,由於obj1中的對象c是一個引用數據類型,拷貝的時候拷貝的是對象的引用。rest
數組的擴展運算符
擴展運算符一樣能夠運用在對數組的操做中。
能夠將數組轉換爲參數序列
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
能夠複製數組
若是直接經過下列的方式進行數組複製是不可取的:
const arr1 = [1, 2];
const arr2 = arr1;
arr2[0] = 2;
arr1 // [2, 2]
緣由上面已經介紹過,用擴展運算符就很方便:
const arr1 = [1, 2];
const arr2 = [...arr1];
仍是記住那句話:擴展運算符(…)用於取出參數對象中的全部可遍歷屬性,拷貝到當前對象之中,這裏參數對象是個數組,數組裏面的全部對象都是基礎數據類型,將全部基礎數據類型從新拷貝到新的數組中。
擴展運算符能夠與解構賦值結合起來,用於生成數組
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
須要注意的一點是:
若是將擴展運算符用於數組賦值,只能放在參數的最後一位,不然會報錯。
const [...rest, last] = [1, 2, 3, 4, 5];
// 報錯
const [first, ...rest, last] = [1, 2, 3, 4, 5];
// 報錯
擴展運算符還能夠將字符串轉爲真正的數組
[...'hello']
// [ "h", "e", "l", "l", "o" ]
任何 Iterator 接口的對象(參閱 Iterator 一章),均可以用擴展運算符轉爲真正的數組
這點說的比較官方,你們具體能夠參考阮一峯老師的ECMAScript 6入門教程。
比較常見的應用是能夠將某些數據結構轉爲數組,好比:
// arguments對象
function foo() {
const args = [...arguments];
}
用於替換es5中的Array.prototype.slice.call(arguments)寫法。