1. 屬性的簡潔表示法
ES6 允許在大括號里面霸株,直接寫入變量和函數(shù),作為對象的屬性和方法集乔。這樣的書寫更加簡潔去件。
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
當然,除了屬性可以簡寫扰路,方法也可以簡寫尤溜,比如:
const obj = {
print (param) {
console.log(param)
}
}
2. 屬性名表達式
我們知道,讀取對象的屬性時可通過obj.key
或者obj[key]
這兩種方式汗唱,不同的是第一種方式key
必須是一個確定的鍵名宫莱,而第二種方法的key
可以是確定的鍵名也能使一個表達式
let [key, age] = ['name', 23]
let obj = {
[key]: 'bing',
age: age
}
obj // {name: "bing", age: 23}
let obj = {
[key]: 'bing',
[age]: age
}
obj // {name: "bing", 23: 23}
通過上面的代碼可以看出來,如果給給對象的鍵名加上[]
渡嚣,對象的鍵名就會變成一個JavaScript
表達式梢睛,表達式計算出來的值就是對象的鍵名,如果上述例子不能很好理解识椰,看下面這個例子:
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
a[lastWord]
與a['last word']
的值是一樣的绝葡,因為lastWord
變量的值就是last word
,所以這兩個值其實是一個對象的同一個鍵名對應(yīng)的值腹鹉。
需要注意的是如果表達式是一個對象藏畅,默認情況下會自動將對象轉(zhuǎn)為字符串[object Object]
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}
3. 方法的 name 屬性
對象的方法也是函數(shù),因此也有name
屬性
const obj = {
print () {
console.log('hello world')
}
}
obj.print.name // print
如果對象的方法使用了取值函數(shù)(getter)
和存值函數(shù)(setter)
功咒,則name
屬性不是在該方法上面愉阎,而是該方法的屬性的描述對象的get
和set
屬性上面,返回值是方法名前加上get
和set
力奋。
const obj = {
get foo() {},
set foo(x) {}
};
obj.foo.name
// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
有兩種特殊情況:bind
方法創(chuàng)造的函數(shù)榜旦,name
屬性返回bound
加上原函數(shù)的名字;Function
構(gòu)造函數(shù)創(chuàng)造的函數(shù)景殷,name
屬性返回anonymous
溅呢。
(new Function()).name // "anonymous"
var doSomething = function() {
// ...
};
f = doSomething.bind(this)
f.name // "bound doSomething"
4. 屬性的可枚舉性
對象的每個屬性都有一個描述對象澡屡,用來控制該屬性的行為。Object.getOwnPropertyDescriptor
方法可以獲取該對象的屬性描述對象咐旧,描述對象的enumerable
豎向稱為可枚舉性驶鹉,如果該屬性值為false
,那么就說明該屬性不可枚舉铣墨,即某些操作或忽略該屬性室埋,目前有四個操作會忽略不可枚舉的屬性。
-
for...in
循環(huán):只遍歷對象自身的和繼承的可枚舉的屬性伊约。 -
Object.keys()
:返回對象自身的所有可枚舉的屬性的鍵名姚淆。 -
JSON.stringify()
:只串行化對象自身的可枚舉的屬性。 -
Object.assign()
: 忽略enumerable
為false
的屬性碱妆,只拷貝對象自身的可枚舉的屬性肉盹。
引入可枚舉屬性的目的就在于讓某些屬性可以規(guī)避某些遍歷操作。
由此引發(fā)思考疹尾,當拷貝對象時上忍,我們?nèi)绻麅H僅使用for...in
遍歷了對象的可枚舉屬性,那么不可枚舉屬性就會被遺漏纳本,那么對象拷貝就變得不嚴謹窍蓝,所以我使用Object.getOwnPropertyNames
方法來替代```for...in``直接遍歷對象:
function deepCopy(obj) {
if (obj instanceof Date) { return new Date(obj) }
if (obj instanceof RegExp) { return new RegExp(obj)}
let result = new obj.__proto__.constructor()
for (let key of Object.getOwnPropertyNames(obg) {
if (obj.hasOwnProperty(key) && obj[key] !== obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
result[key] = deepCopy(obj[key]);
} else {
result[key] = obj[key];
}
}
}
return result;
}
5. super 關(guān)鍵字
ES6 新增了關(guān)鍵字super,指向當前對象的原型對象繁成。
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
值得注意的是super
關(guān)鍵字只能用在對象的方法中吓笙,用在其他任何地方都會報錯。
// 報錯
const obj = {
foo: super.foo
}
// 報錯
const obj = {
foo: () => super.foo
}
// 報錯
const obj = {
foo: function () {
return super.foo
}
}
上面三種super的用法都會報錯巾腕,因為對于 JavaScript
引擎來說面睛,這里的super
都沒有用在對象的方法之中。第一種寫法是super
用在屬性里面尊搬,第二種和第三種寫法是super
用在一個函數(shù)里面叁鉴,然后賦值給foo
屬性。目前佛寿,只有對象方法的簡寫法可以讓 JavaScript
引擎確認幌墓,定義的是對象的方法。
6. 對象的擴展運算符
之前在數(shù)組的擴展中介紹了擴展運算符(...
)冀泻,ES2018將這個運算符引入了對象常侣,因為數(shù)組是一種特殊的對象,所以理論上弹渔,擴展運算符本就應(yīng)該應(yīng)用于對象中胳施。
6.1 使用擴展運算符解構(gòu)賦值
let obj = {
name: 'bing',
age: 23,
id: 007
}
let {name, ...rest} = obj
name // 'bing'
rest // {age: 23, id: 7}
6.2 使用擴展運算符淺拷貝對象
對象的擴展運算符用于取出參數(shù)對象的所有可遍歷屬性,拷貝到當前對象之中肢专。
let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}
如果擴展運算符后面是字符串巾乳,它會自動轉(zhuǎn)成一個類似數(shù)組的對象您没,因此返回的不是空對象。
{...'hello'}
// {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
跟數(shù)組一樣胆绊,擴展運算符還可以合并兩個對象
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);
如果對象中有重復(fù)的鍵值,那么后面的會覆蓋前面的欧募,相當于重復(fù)賦值压状。
let obj1 = {name:'bing'}
let obj2 = {name: 'yan'}
let obj = {...obj1, ...obj2}
obj // {name: "yan"}