展开运算符是什么
展开运算符,也叫扩展运算符,常用...表示,一般用来复制、拼接、修改数组或对象。举个栗子:
const arr1 = [0, 1, 2]
const arr2 = [3, 4, 5]
const arr3 = [...arr1, ...arr2] //[0,1,2,3,4,5]
const obj1 = {a:1}
const obj2 = {b:2}
const obj3 = {...obj1, ...obj2} //{a:1, b:2}
一个误会———必须要具有iterator
在阮一峰的ES6教程关于iterator的应用里有这么一个段话:
第一次看的时候,误解为展开运算符的使用要依靠iterator来实现。然而不是这样的。真实的情况应该是,数组使用展开运算符确实需要iterator接口,但是对象使用的时候调用机制不同,不依赖于iterator。
浅析
首先,通过babel来测试一下它是怎么实现的:
// 编译前:
function test() {
const obj = { a: 1 };
const arr = [1, 2, 3];
console.log([...arr]);
console.log({ ...obj });
debugger;
}
// babel编译后:
("use strict");
var _interopRequireDefault = require("./node_modules/@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.test = test;
require("core-js/modules/es7.object.get-own-property-descriptors");
require("core-js/modules/web.dom.iterable");
require("core-js/modules/es6.object.keys");
var _defineProperty2 = _interopRequireDefault(
require("./node_modules/@babel/runtime/helpers/defineProperty")
);
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly)
symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function(key) {
(0, _defineProperty2.default)(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(
target,
key,
Object.getOwnPropertyDescriptor(source, key)
);
});
}
}
return target;
}
function test() {
var obj = {
a: 1
};
var arr = [1, 2, 3];
console.log([].concat(arr));
console.log(_objectSpread({}, obj));
debugger;
}
上面这段代码写了数组和对象使用展开运算符后babel编译结果。可以看出,同样的展开运算符,数组和对象的处理方法是不一样的。数组中的展开运算符用过concat实现,而对象就是通过循环遍历得到。
在MDN中关于展开运算符可以看到这样一个描述:
也就是说,对象内使用展开运算符拷贝合并属性,是es的特性。
总结
数组内使用展开运算符要调用iterator接口,而对象内使用展开运算符是es标准中赋予的特性,它就是能够被展开。