一巡扇、屬性的簡介表示法
(1)ES6 允許直接寫入變量和函數(shù),作為對象的屬性和方法炊琉。這樣的書寫更加簡潔
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
上面代碼表明展蒂,ES6 允許在對象之中又活,直接寫變量。這時锰悼,屬性名為變量名, 屬性值為變量的值柳骄。下面是另一個例子。
(2)方法簡寫
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
(3)屬性的賦值器(setter)和取值器(getter)簡寫箕般。
const cart = {
_wheels: 4,
get wheels () {
return this._wheels;
},
set wheels (value) {
if (value < this._wheels) {
throw new Error('數(shù)值太小了耐薯!');
}
this._wheels = value;
}
}
注意,簡潔寫法的屬性名總是字符串丝里,這會導致一些看上去比較奇怪的結(jié)果
const obj = {
class () {}
};
// 等同于
var obj = {
'class': function() {}
};
二曲初、屬性名表達式
(1)、JavaScript 定義對象的屬性杯聚,有兩種方法臼婆。
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
上面代碼的方法一是直接用標識符作為屬性名,方法二是用表達式作為屬性名幌绍,這時要將表達式放在方括號之內(nèi)
(2)颁褂、表達式用于定義方法名
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
注意,屬性名表達式與簡潔表示法纷捞,不能同時使用痢虹,會報錯。
三主儡、Object.is()比較兩個值是否相等
ES5 比較兩個值是否相等奖唯,只有兩個運算符:相等運算符(==)和嚴格相等運算符(===)世舰。它們都有缺點愕难,前者會自動轉(zhuǎn)換數(shù)據(jù)類型,后者的NaN不等于自身属提,以及+0等于-0寂汇。
Object.is用來比較兩個值是否嚴格相等病往,與(===)的行為基本一致
不同之處只有兩個:一是+0
不等于-0
,二是NaN
等于自身骄瓣。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
四停巷、Object.assign() 對象合并
1.基本用法
Object.assign
將源對象(source)的所有可枚舉屬性,復制到目標對象(target)榕栏。
注意畔勤,如果目標對象與源對象有同名屬性,或多個源對象有同名屬性扒磁,則后面的屬性會覆蓋前面的屬性庆揪。
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
(1)如果該參數(shù)不是對象,則會先轉(zhuǎn)成對象妨托,然后返回缸榛。
typeof Object.assign(2) // "object"
(2)undefined和null無法轉(zhuǎn)成對象吝羞,所以如果它們作為參數(shù),就會報錯内颗。
Object.assign(undefined) // 報錯
Object.assign(null) // 報錯
(3)非對象參數(shù)出現(xiàn)在源對象的位置(即非首參數(shù))首先钧排,這些參數(shù)都會轉(zhuǎn)成對象,如果無法轉(zhuǎn)成對象起暮,就會跳過卖氨。undefined和null不在首參數(shù)会烙,就不會報錯负懦。
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
(4)其他類型的值(即數(shù)值、字符串和布爾值)不會產(chǎn)生效果
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const obj = Object.assign({}, v1, v2, v3);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
上面代碼中柏腻,v1纸厉、v2、v3分別是字符串五嫂、布爾值和數(shù)值颗品,結(jié)果只有字符串合入目標對象(以字符數(shù)組的形式),數(shù)值和布爾值都會被忽略沃缘。
Object.assign
拷貝的屬性是有限制的躯枢,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性
注意點
(1)淺拷貝
Object.assign
方法實行的是淺拷貝槐臀,而不是深拷貝
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
上面代碼中锄蹂,obj1的a屬性的值是一個對象,Object.assign拷貝得到的是這個對象的引用
(2)同名屬性的替換
對于這種嵌套的對象水慨,一旦遇到同名屬性得糜,Object.assign
的處理方法是替換,而不是添加晰洒。
const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
(3)數(shù)組的處理
Object.assign
可以用來處理數(shù)組朝抖,但是會把數(shù)組視為對象。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
上面代碼中谍珊,Object.assign把數(shù)組視為屬性名為 0治宣、1、2 的對象砌滞,因此源數(shù)組的 0 號屬性4覆蓋了目標數(shù)組的 0 號屬性1侮邀。
(4)取值函數(shù)的處理
Object.assign
只能進行值的復制,如果要復制的值是一個取值函數(shù)布持,那么將求值后再復制豌拙。
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
常見用途
可枚舉性
(1)為對象添加屬性
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
上面方法通過Object.assign
方法,將x
屬性和y
屬性添加到Point
類的對象實例
(2)為對象添加方法
(3)克隆對象
function clone(origin) {
return Object.assign({}, origin);
}
上面代碼將原始對象拷貝到一個空對象题暖,就得到了原始對象的克隆按傅。
(4)合并多個對象
將多個對象合并到某個對象捉超。
const merge =
(target, ...sources) => Object.assign(target, ...sources);
五唯绍、屬性的可枚舉性和遍歷
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
描述對象的enumerable
屬性拼岳,稱為”可枚舉性“,如果該屬性為false
况芒,就表示某些操作會忽略當前屬性惜纸。
目前,有四個操作會忽略enumerable為false的屬性绝骚。
for...in
循環(huán):只遍歷對象自身的和繼承的可枚舉的屬性耐版。
Object.keys()
:返回對象自身的所有可枚舉的屬性的鍵名。
JSON.stringify()
:只串行化對象自身的可枚舉的屬性压汪。
Object.assign()
: 忽略enumerable
為false
的屬性粪牲,只拷貝對象自身的可枚舉的屬性。
屬性的遍歷
(1)for...in
for...in
循環(huán)遍歷對象自身的和繼承的可枚舉屬性(不含 Symbol
屬性)止剖。
(2)Object.keys(obj)
Object.keys
返回一個數(shù)組腺阳,包括對象自身的(不含繼承的)所有可枚舉屬性(不含 Symbol
屬性)的鍵名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames
返回一個數(shù)組穿香,包含對象自身的所有屬性(不含 Symbol
屬性亭引,但是包括不可枚舉屬性)的鍵名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
返回一個數(shù)組皮获,包含對象自身的所有 Symbol 屬性的鍵名焙蚓。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys
返回一個數(shù)組,包含對象自身的所有鍵名魔市,不管鍵名是 Symbol
或字符串主届,也不管是否可枚舉。
六待德、Object.keys()君丁,Object.values(),Object.entries()
Object.keys() 遍歷屬性的鍵名将宪。
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
Object.values()可遍歷屬性的鍵值绘闷。
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
Object.entries 可遍歷屬性的鍵值對數(shù)組。
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
七较坛、對象的擴展運算符
(1)解構(gòu)賦值
const [a, ...b] = [1, 2, 3];
a // 1
b // [2, 3]
由于解構(gòu)賦值要求等號右邊是一個對象印蔗,所以如果等號右邊是undefined或null,就會報錯丑勤,因為它們無法轉(zhuǎn)為對象华嘹。
let { x, y, ...z } = null; // 運行時錯誤
let { x, y, ...z } = undefined; // 運行時錯誤
解構(gòu)賦值必須是最后一個參數(shù),否則會報錯法竞。
(2)擴展運算符
對象的擴展運算符(...)用于取出參數(shù)對象的所有可遍歷屬性耙厚,拷貝到當前對象之中强挫。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
這等同于使用Object.assign
方法。
let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);
如果把自定義屬性放在擴展運算符前面薛躬,就變成了設(shè)置新對象的默認屬性值俯渤。
let aWithDefaults = { x: 1, y: 2, ...a };
// 等同于
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
// 等同于
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
與數(shù)組的擴展運算符一樣,對象的擴展運算符后面可以跟表達式型宝。
const obj = {
...(x > 1 ? {a: 1} : {}),
b: 2,
};
如果擴展運算符后面是一個空對象八匠,則沒有任何效果。
{...{}, a: 1}
// { a: 1 }
如果擴展運算符的參數(shù)是null
或undefined
趴酣,這兩個值會被忽略梨树,不會報錯。
let emptyObject = { ...null, ...undefined }; // 不報錯