es6 物件的擴充套件,物件的解構和深拷貝
物件的擴充套件
屬性的簡潔表示法
ES6 允許直接寫入變數和函式,作為物件的屬性和方法。這樣的書寫更加簡潔。
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同於
const baz = {foo: foo};
方法也可以簡寫。
const o = {
method() {
return "Hello!";
}
};
// 等同於
const o = {
method: function() {
return "Hello!";
}
};
屬性名錶達式
JavaScript 定義物件的屬性,有兩種方法。
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
但是,如果使用字面量方式定義物件(使用大括號),在 ES5 中只能使用方法一(識別符號)定義屬性。
var obj = {
foo: true,
abc: 123
};
ES6 允許字面量定義物件時,用方法二(表示式)作為物件的屬性名,即把表示式放在方括號內。
let propKey = 'foo';
let obj = {
[propKey]: true,//等價於 foo:true
['a' + 'bc']: 123
};
表示式還可以用於定義方法名。
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
注意,屬性名錶達式與簡潔表示法,不能同時使用,會報錯。
// 報錯
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };
// 正確
const foo = 'bar';
const baz = { [foo]: 'abc'};
Object.is()
ES5 比較兩個值是否相等,只有兩個運算子:相等運算子(==
)和嚴格相等運算子(===
)。它們都有缺點,前者會自動轉換資料型別,後者的NaN
NaN
是S5裡面在”===”符號下唯一一個自己都不等於自己的型別),以及+0
等於-0
。JavaScript 缺乏一種運算,在所有環境中,只要兩個值是一樣的,它們就應該相等。
ES6 提出同值相等演算法,用來解決這個問題。Object.is
就是部署這個演算法的新方法。它用來比較兩個值是否嚴格相等,與嚴格比較運算子(===)的行為基本一致。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
不同之處只有兩個:一是+0
不等於-0
,二是NaN
等於自身。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.assign()
Object.assign
方法用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target),順序就是引數順序。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
如果只有一個引數,Object.assign
會直接返回該引數。
const obj = {a: 1};
Object.assign(obj) === obj // true
由於undefined
和null
無法轉成物件,所以如果它們作為引數,就會報錯。
Object.assign(undefined) // 報錯
Object.assign(null) // 報錯
注意:Object.assign
可以用來處理陣列,但是會把陣列視為物件。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//把陣列視為屬性名為 0、1、2 的物件,因此源陣列的 0 號屬性4覆蓋了目標陣列的 0 號屬性1。
Object.keys()
ES5 引入了Object.keys
方法,返回一個數組,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名。
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
ES2017 引入了跟Object.keys
配套的Object.values
和Object.entries
,作為遍歷一個物件的補充手段,供for...of
迴圈使用。
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
Object.values()
Object.values
方法返回一個數組,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值。
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
返回陣列的成員順序,
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
上面程式碼中,屬性名為數值的屬性,是按照數值大小,從小到大遍歷的,因此返回的順序是b
、c
、a
。
Object.entries
Object.entries
方法返回一個數組,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值對陣列。
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
除了返回值不一樣,該方法的行為與Object.values
基本一致。
物件的擴充套件運算子
解構賦值
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
由於解構賦值要求等號右邊是一個物件,所以如果等號右邊是undefined
或null
,就會報錯,因為它們無法轉為物件。
let { x, y, ...z } = null; // 執行時錯誤
let { x, y, ...z } = undefined; // 執行時錯誤
解構賦值必須是最後一個引數,否則會報錯。
let { ...x, y, z } = obj; // 句法錯誤
let { x, ...y, ...z } = obj; // 句法錯誤
注意,解構賦值的拷貝是淺拷貝,即如果一個鍵的值是複合型別的值(陣列、物件、函式)、那麼解構賦值拷貝的是這個值的引用,而不是這個值的副本。
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
擴充套件運算子
擴充套件運算子(...
)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
這等同於使用Object.assign
方法。
let aClone = { ...a };
// 等同於
let aClone = Object.assign({}, a);
物件的深拷貝
- 物件的深拷貝呢就是:當物件裡存在陣列或者其他物件作為屬性時,通過某些方法將內部的陣列或物件進行展開的操作!
//{a:1,b:2,{c:3,d:4}}
var deepCopy = function ( obj , deep ) {
var o = obj instanceof Array?[]:{};
for(var k in obj ) {
var val = obj[k];
if(deep && typeof val === "object" ){
o[k] = deepCopy(val,deep);
}else{
o[k] = val;
}
}
return o;
}