### 屬性的簡潔表示法
ES6允許直接寫入變量和函數作為對象的屬性和方法,這樣書寫更加簡潔
```js
let foo = 'bar'
let obj = { foo }
obj // { foo: 'bar' }
```
ES6允許在對象中只寫屬性名,不寫屬性值,這時,屬性值等于屬性名所代表的變量
### 屬性名表達式
ES6允許字面量定義對象時使用表達式,即把表達式放在方括號內
```js
obj['a' + 'bc'] = 123
```
### 方法的name屬性
函數的`name`屬性返回函數名。對象的方法也是函數,因此也有`name`屬性
```js
const person = {
sayName () {
console.log('hello')
}
}
person.sayName.name // 'sayName'
```
如果對象的方法使用了取值函數(`getter`)和存值函數(`setter`),則`name`屬性不是在該方法上,而是在該方法屬性的描述對象的`get`和`set`屬性上。
### Object.is()
在ES5中,比較兩個值是否相等,可以使用`==`和`===`,相等運算符會自動轉換數據類型,而嚴格相等運算符會認為`NaN`不等于自身,以及`+0`等于`-0`。
ES6新增了`Object.is()`方法來解決這個問題。它用來比較兩個值是否嚴格相等,與`===`的行為基本一致。
```js
Object.is('foo', 'foo') //true
Object.is({}, {}) //false
```
```js
+0 === -0 // true
NaN === NaN //false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
```
### Object.assign
`Object.assign`方法用于將源對象的所有可枚舉屬性復制到目標對象
```js
let target = { a: 1 }
let source1 = { b: 2 }
let source2 = { c: 3 }
Object.assing(target, source1, source2)
target // { a: 1, b: 2, c: 3 }
```
`Object.assign`方法的第一個參數是目標對象,后面的都是源對象
`Object.assign`方法實行的是淺復制,而不是深復制,也就是說,如果源對象某個屬性的值是對象,那么目標對愛那個復制得到的是這個對象的引用。
```js
let obj1 = { a: { b: 1 } }
let obj2 = Object.assign({}, obj1)
obj1.a.b = 2
obj2.a.b // 2
```
`Object.assign`方法的常見用途:
#### 為對愛那個添加屬性
```js
class Point {
constructor (x, y) {
Object.assign(this, { x, y })
}
}
```
#### 為對象添加方法
```js
Object.assign(SomeClass.prototype, {
someMethod (arg1, arg2) {
...
}
})
```
#### 克隆對象
```js
function clone (origin) {
return Object.assign({}, origin)
}
```
上面的方法不能克隆繼承值,只能克隆自身的值。
#### 合并多個對象
```js
const merge= (target, ...sources) => Object.assign(target, ...sources)
```
### 屬性的可枚舉性
對象的每一個屬性都具有一個描述對象(Descriptor),用于控制該屬性的行為。
`Object.getOwnPropertyDescriptor` 方法可以獲取該屬性的描述對象
```js
let obj = { foo: 123 }
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
```
### 屬性的遍歷
ES6一共有5中方法可以遍歷對象的屬性
- `for...in` 它遍歷對象自身和繼承的可枚舉屬性
- `Object.keys(obj)` 它返回一個數組,包含對象自身的,不包含繼承的,所有可枚舉屬性
- `Object.getOwnPropertyNames(obj)` 返回一個數組,包含對象自身的所有屬性,包含不可枚舉屬性
- `Object.getOwnPropertySymbols(obj)` 返回一個數組,包含對象自身所有Symbol屬性
- `Reflect.ownKeys(obj)` 返回一個數組,包含對象自身所有屬性,包括Symobl,不管是否可枚舉
### __proto__屬性、Object.setPrototpyeOf()、Object.getPrototypeOf()
#### __proto__屬性
`__proto__`屬性用來讀取和設置當前對象的 `prototype`對象
```js
let obj = {
method: function () { ... }
}
obj.__proto__ = someOtherObj
```
最佳實踐證明,無論從那個角度上來講,請都不要使用這個屬性,而是使用`Object.setPrototpyeOf()`來執行寫操作,`Object.getPrototypeOf()`來執行讀操作,`Object.create()`來執行生成操作。
#### Object.setPrototypeOf()
ES6推薦使用 `Object.setPrototypeOf()` 方法來設置原型對象,它返回對象本身。
```js
// 用法
let o = Object.setPrototypeOf({}, null)
```
```js
let proto = {}
let obj = { x: 10 }
Object.setPrototypeOf(obj, proto)
proto.y = 20
proto.z = 40
obj.x // 10
obj.y // 20
obj.z // 40
```
#### Object.getPrototypeOf()
`Object.gfetPrototpyeOf()`方法用于讀取一個對象的`prototype`對象
```js
function Rectangle () {}
let rec = new Rectangle()
Object.getPrototypeOf(rec) === Rectangle.prototype // true
```
### Object.keys()、Object.values()、Object.entries()
#### Object.keys()
`Object.keys()`方法返回一個數組,成員是參數對象自身的,不包含繼承的,所有可遍歷屬性的鍵名
```js
let obj = { foo: 'bar', baz: 42 }
Object.keys(obj)
// ['foo', 'baz']
```
#### Object.values()
`Object.values()`方法返回一個數組,成員是參數對象自身的,不包含繼承的,所有可遍歷屬性的鍵值
```js
let obj = { foo: 'baz', bar: 42 }
Object.values(obj)
// ['baz', 42]
```
#### Object.entries()
`Object.entries()`方法返回一個數組,成員是參數對象自身的,不包含繼承的,所有可遍歷屬性的鍵值對數組
```js
let obj = { foo: 'bar', baz: 42 }
Object.entries(obj)
// [ ['foo', 'baz'], ['bar', 42] ]
```
### 對象的擴展運算符
前面我們介紹了擴展運算符
```js
const [a, ...b] = [1, 2, 3]
a // 1
b // [2, 3]
```
ES2017將這個特性引入到了對象之中。
對象的解構賦值用于從一個對象取值,相當于將所有可遍歷、但未被讀取的屬性分配到指定的對象上面。
```js
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }
x // 1
y // 2
z // { a: 3, b: 4 }
```
擴展運算符(...)用于取出參數對象的所有可遍歷屬性,并將其復制到當前對象中
```js
let z = { a: 3, b: 4 }
let n = { ...z }
n // { a: 3, b: 4 }
```
### Object.getOwnPropertyDescriptors()
ES5的`Object.getOwnPropertyDescriptor()`方法用來返回某個對象屬性的描述對象。ES2017引入了`Object.getOwnPropertyDescriptors()`方法,返回指定對象所有自身屬性(非繼承屬性)的描述對象。