JavaScript(ES6)之擴充套件運算子
物件的擴充套件運算子
理解物件的擴充套件運算子其實很簡單,只要記住一句話就可以:
物件中的擴充套件運算子(...)用於取出引數物件中的所有可遍歷屬性,拷貝到當前物件之中
let bar = { a: 1, b: 2 };
let baz = { ...bar };
console.log(baz) // { a: 1, b: 2 }
上述方法中實際上就等價於:
let bar = { a: 1, b: 2 };
let baz = Object.assign({}, bar);
console.log(baz) // { a: 1, b: 2 }
Object.assign
方法用於物件的合併,將源物件(source
target
)。
Object.assign
方法的第一個引數是目標物件,後面的引數都是源物件。(如果目標物件與源物件有同名屬性,或多個源物件有同名屬性,則後面的屬性會覆蓋前面的屬性)。
同樣,如果使用者自定義的屬性,放在擴充套件運算子後面,則擴充套件運算子內部的同名屬性會被覆蓋掉。
let bar = {a: 1, b: 2};
let baz = {...bar, ...{a:2, b: 4}};
console.log(baz) // {a: 2, b: 4}
利用上述特性就可以很方便的修改物件的部分屬性。在redux
中的reducer函式規定必須是一個純函式(如果不是很清楚什麼是純函式的可以參考reducer
中的state
物件要求不能直接修改,可以通過擴充套件運算子把修改路徑的物件都複製一遍,然後產生一個新的物件返回。
這裡有點需要注意的是擴充套件運算子對物件例項的拷貝屬於一種淺拷貝。肯定有人要問什麼是淺拷貝?我們知道javascript
中有兩種資料型別,分別是基礎資料型別和引用資料型別。基礎資料型別是按值訪問的,常見的基礎資料型別有Number
、String
、Boolean
、Null
、Undefined
,這類變數的拷貝的時候會完整的複製一份;引用資料型別比如Array
,在拷貝的時候拷貝的是物件的引用,當原物件發生變化的時候,拷貝物件也跟著變化,比如:
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
,如果改成這樣:
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
是一個引用資料型別,拷貝的時候拷貝的是物件的引用。如果不想拷貝物件的引用,可以用最笨的方法:
let obj1 = {a:1,b:2,c:{nickName: 'c'}}
let obj2 = {...obj1, c: {nickName: 'd'}}
console.log(obj1, obj2) // {a: 1, b: 2c: {nickName: 'c'} // {a: 1, b: 2, c: {nickName: 'd'}}
obj2.c.nickName = 'g'
console.log(obj1, obj2) // {a: 1, b: 2c: {nickName: 'c'} // {a: 1, b: 2, c: {nickName: 'g'}}
// 這樣修改obj2的值不會影響到obj1的值
......後續補充