解构原理
const obj = {
id: 1
name: 'xxx',
age: 20
children: {
id: 2,
name: 'yyy',
age: 18
}
}
const { id, children, ...rest } = obj
在这里,解构出来的 id 和 children 其实是一个全新的赋值,等同于:
let id = obj.id, children = obj.children
所以不管怎么修改 id,都不会对原对象的 id 造成改变。但值得一提的是,解构出来的对象属于是浅拷贝,指向的都是同一个地址,当对解构出来的 children 对象里的值进行修改,在原对象的 children 里的值也会被改变。
children.id = 3
// 输出 obj
const obj = {
id: 1,
name: 'xxx',
children: {
id: 3,
name: 'yyy',
age: 18
}
}
剩余参数的解构原理
const obj = {
id: 7,
name: 'xxx',
age: 18,
[Symbol("syb")]: 123,
};
为了更清楚的说明剩余参数的解构原理,我们可以通过 babel 把上述代码编译为 ES5 代码来看一下。
function _objectWithoutProperties(source, excluded)
{
if (source == null) return {};
// 获取除了 symbol 的所有参数
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols)
{
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++)
{
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded)
{
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++)
{
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var obj = _defineProperty(
{
id: 7,
name: 'xxx',
age: 18,
},
Symbol('syb'),
123
);
var name = obj.name,
rest = _objectWithoutProperties(obj, ['name']);
在 _objectWithoutPropertiesLoose 函数中可以很清楚的看到,这里先是把传进来的对象先通过 Object.keys 提取出 key ,再遍历取出除了 excluded 以外的所有 key 的值。然后因为 Object.keys 方法只会返回一个对象的自身可枚举属性组成的数组,它不会返回对象的 Symbol 属性。这是因为 Symbol 属性被设计为不可枚举的,所以它们不会被 Object.keys() 方法遍历到。
所以需要通过 Object.getOwnPropertySymbols() 方法获取对象中的所有 Symbol 属性,再进行比较赋值。最后得到除了 exclude 外的所有属性。
总结
对象结构语法是创建对象 -> 枚举属性 -> 复制属性,跟迭代器没有关系。