对象
对象的扩展
对象的扩展运算符
- 扩展运算符
...
应用场景- 解构赋值 ```javascript // 案例一:解构赋值 let { x, y, …z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }
// 解构赋值是浅拷贝 let a = { foo: { bar: 1 } }
let b = { …a }; a.foo.bar = 5; b.foo.bar; // 5
// 可以正确拷贝set和get方法 let obj = { _val: 0, get val() { return this._val }, set val(val) { this._val = val } };
let test = { …obj }
test.val = 100 console.log(test.val); // 100 console.log(obj.val); // 0
```javascript
// 案例二:错误的解构赋值
// 解构赋值要求等号右边是一个对象
let { ...z } = null; // 运行时错误
let { ...z } = undefined; // 运行时错误
// 解构赋值必须是最后一个参数,否则会报错
let { ...x, y, z } = someObject; // 句法错误
let { x, ...y, ...z } = someObject; // 句法错误
// 扩展运算符的解构赋值,不能复制 那些从原型对象继承来的属性
// 案例三
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
/**
* o2 = {
* b: 2,
* __proto__: { a: 1 }
* }
*/
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined
// 案例四
const o = Object.create({ x: 1, y: 2 });
o.z = 3;
/**
* o = {
* z: 3,
* __proto__: { x: 1, y: 2 }
* }
*/
let { x, ...newObj } = o;
let { y, z } = newObj;
x // 1 因为 x 是 直接解构赋值,所以能拿到
y // undefined y 是 扩展对象得到newObj,然后再解构赋值,这时候newObj没有y属性
z // 3
newObj // { z: 3 }
// 案例五:对象的扩展运算符
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
// 由于数组是特殊的对象,所以对象的扩展运算符也可以用于数组
let foo = { ...['a', 'b', 'c'] };
foo // {0: "a", 1: "b", 2: "c"}
{...{}, a: 1} // { a: 1 }
// 如果扩展运算符后面不是对象,则会自动将其转为对象
{...1} // 等同于 {...Object(1)} 结果是 {}
{...true} // // 等同于 {...Object(true)} 结果是 {}
{...undefined} // 等同于 {...Object(undefined)} 结果是 {}
{...null} // 等同于 {...Object(null)} 结果是 {}
// 如果扩展运算符后面是字符串,它会自动转成一个类似数组的对象
{...'hello'} // {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
// 案例六:拷贝对象的同时,拷贝其原型
// 写法一的__proto__属性在非浏览器的环境不一定部署,因此推荐使用写法二和写法三
// 写法一
const clone1 = {
__proto__: Object.getPrototypeOf(obj),
...obj
};
// 写法二
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)),
obj
);
// 写法三
const clone3 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)