### 属性的简洁表示法
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()`方法,返回指定对象所有自身属性(非继承属性)的描述对象。