// Spread可以在构造字面量对象时,将对象表达式按 key-value 的方式展开
// 情况1:
// let a = { test: '', ...obj }; // 编译前
// var a = _objectSpread({ test: '' }, obj); // 编译后
// 情况2:
// let a = { ...obj, test: '' }; // 编译前
// var a = _objectSpread(_objectSpread({}, obj), {}, { test: '' }); // 编译后 中间的{}??
/**
* 看了_objectSpread:_objectSpread({}, obj, {test: ''})其实也能达到同样的效果
*/
function _typeof(obj) {
"@babel/helpers - typeof";
return _typeof =
"function" == typeof Symbol && "symbol" == typeof Symbol.iterator // 检查原生js是否支持Symbol类型
? function (obj) { return typeof obj; }
: function (obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype
? "symbol" : typeof obj;
},
_typeof(obj);
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object); // 只能拿到String类型的key,已过滤不可枚举的key
// 获取类型为Symbol的key-并手动过滤enumerable为false的
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
enumerableOnly && (symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
})), keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread(target) {
// 第一个入参为target,从第二个参数开始,属性都扩展到target上
for (var i = 1; i < arguments.length; i++) {
var source = null != arguments[i] ? arguments[i] : {};
i % 2
?
ownKeys(Object(source), !0).forEach(function (key) { // 请先查看——备用1
_defineProperty(target, key, source[key]);
})
:
Object.getOwnPropertyDescriptors
?
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))
:
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
/**
* 将一个对象的所有属性都扩展给另一个对象,这里使用了两种方式:
*
* 1. 枚举key,设置每一个属性
* |__Object.keys() / ownKeys()
* |__没有直接使用=进行赋值
*
* 2. 批量设置:Object.defineProperties
* |__Object.getOwnPropertyDescriptors可以获取到所有描述(包括Symbol类型的key)
* |__但是扩展运算符扩展出来的属性的描述全都是默认的,enumerable\configurable\writable都为true,而且没有setter和getter
* |__而且会获取到所有属性描述,包括不可枚举的
* |__但是用户的对象无法保证descriptor是什么,所以对于用户要扩展的对象不能使用这种批量设置的方式,只能枚举key
* |__请先查看——备用2
* |__奇数:用户的——枚举key; 偶数:自创的——批量设置
*
*
* let a = { test: '', ...obj }; // 编译前
* var a = _objectSpread({ test: '' }, obj); // 编译后
*
* let a = { ...obj, test: '' }; // 编译前
* var a = _objectSpread(_objectSpread({}, obj), {}, { test: '' }); // 编译后
*/
/**
* 为啥要使用2种,不能全都枚举key吗
*/
}
return target;
}
function _defineProperty(obj, key, value) {
// 修改obj的key属性值为value
key = _toPropertyKey(key); // 校验key的合法性:Symbol和String类型
if (key in obj) {
Object.defineProperty(obj, key, {
value: value, enumerable: true, configurable: true, writable: true
});
} // 请先查看——备用4
else { obj[key] = value; }
return obj;
/**
* configurable: true才能重复defineProperty,不然会报错
* 不过由于target都是我们自己创建的对象,所以都是可配置的
*/
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return _typeof(key) === "symbol" ? key : String(key);
}
function _toPrimitive(input, hint) {
if (_typeof(input) !== "object" || input === null)
return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (_typeof(res) !== "object")
return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
// #region 备用1-ownKeys
var symb = Symbol('name'),
symb1 = Symbol('fixed'),
obj = { name: 'wxm', [symb]: 'key为symbol' };
Object.defineProperty(obj, 'fixed', { value: true, configurable: true, writable: true, enumerable: false });
Object.defineProperty(obj, symb1, { value: 'readonly', configurable: true, writable: true, enumerable: false });
// #endregion
// #region 备用2-getOwnPropertyDescriptors
var obj = {};
var v = '';
Object.defineProperty(obj, 'width', {
enumerable: true,
configurable: true,
set(value) {
console.log('setting width');
v = value;
},
get() {
return v;
}
});
Object.getOwnPropertyDescriptors(obj);
var obj2 = { ...obj };
Object.getOwnPropertyDescriptors(obj2);
// #endregion
// #region 备用3-批量还是循环
function keysTest(target, source) {
ownKeys(Object(source), !0).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
}
function batchTest(target, source) {
Object.getOwnPropertyDescriptors
?
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))
:
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
var object = {};
for (let i = 0; i < 10000; i++) {
object[i] = {};
}
console.time('enum');
keysTest({}, object);
console.timeEnd('enum');
console.time('batch');
batchTest({}, object);
console.timeEnd('batch');
// #endregion
// #region 备用4-赋值失败
var obj = {};
Object.defineProperty(obj, 'width', {
value: 100,
enumerable: true,
configurable: true,
writable: false
});
obj.width = 200; // 修改失败
Object.defineProperty(obj, 'width', {
value: 200,
enumerable: true,
configurable: true,
writable: true
});
// #endregion
// 1. 解构对象的时候,enumerable为false的属性以及Descriptor的getter和setter都是不会被复制的
// 2. 获取对象的所有key时不要忘了Symbol类型的key
// 3. 复制一个对象的属性还有这种方式:Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))
// 4. 给属性值赋值时也许会不成功
网友评论