var _assign = require('object-assign');
对应es6的Object.assign合并两个对象的属性。
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
'use strict';
/* eslint-disable no-unused-vars */
// 获取对象的Symbols属性方法
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
// 用来判断某个对象是否含有指定的属性,和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
var hasOwnProperty = Object.prototype.hasOwnProperty;
// propertyIsEnumerable() 方法返回一个布尔值,表示指定的属性是否可枚举。通过原型链继承的属性除外。
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
// 构造函数创建一个对象包装器。
function toObject(val) {
// 如果值是null或undefined抛出错误,否则会创建一个空对象
// 下面的例子将一个空的 Object 对象存到 o 中:
// var o = new Object();
// var o = new Object(undefined);
// var o = new Object(null);
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
// 返回转换后的对象
return Object(val);
}
// 是否使用原生属性
function shouldUseNative() {
try {
// 如果不支持es6的Object.assign语法返回false
if (!Object.assign) {
return false;
}
// 检测老V8版本中有bug的属性枚举顺序。
// Detect buggy property enumeration order in older V8 versions.
// Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名
// (包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
// Object.getOwnPropertyNames(test1) = ["0", "1", "2", "length"]
test1[5] = 'de';
// Object.getOwnPropertyNames(test1) = ["0", "1", "2", "5", "length"]
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
// 给对象test2添加属性,对应的val值是从0~10
for (var i = 0; i < 10; i++) {
// 静态 String.fromCharCode() 方法返回由指定的UTF-16代码单元序列创建的字符串。
test2['_' + String.fromCharCode(i)] = i;
}
// 遍历test2的属性名,返回对应的值,生成一个新的数组order2
// order2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
// 如果属性名和值不能一一对应,返回false
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
// test3是一个属性名和值相等的对象
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
// 获取根据test3与一个空对象合并生成的新对象的所有key值,并转换成字符串
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
// 如果浏览器支持es6,就使用原生的,否则需要兼容处理
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
// arguments:[target,[...source]]
// arguments[0]=target
for (var s = 1; s < arguments.length; s++) {
// from = source,注意s=1
// to = target
from = Object(arguments[s]);
// 遍历第s个source的key值
for (var key in from) {
// 直接从原型链调用hasOwnProperty,防止对象上有同名自定义属性hasOwnProperty出错
// 只拷贝或覆盖自身的属性,将source的属性添加到target或者把target中同名的属性名的值给覆盖掉
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
// 获取source中的符号属性名
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
// 如果对应得符号属性可枚举,将可枚举的符号属性添加到target
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};