const _String = Object.prototype.toString;
// 获取类型
function getType(item) {
return _String.call(item).slice(8, -1);
}
// 判断类型
function isType(item, type) {
return item && type && item === type;
}
// 考虑值是否是简单对象
// 1,该对象的返回原先必须是对象原型链,就是他自身
// 2.是否为window对象
// 3.是否object类型
function isPlianObejct(obj) {
return (
Object.getPrototypeOf(obj) === Object.prototype &&
isWindow(obj) &&
isType(obj, 'Object')
);
}
// 考虑window是否为window(undefined)的情况
function isWindow(obj) {
return obj != null && obj === obj.window;
}
// 拓展方法
function extend() {
let target = arguments[0] || {},
i = 1,
lens = arguments.length,
deep = false;
let options, //待拷贝容器
name, // 待拷贝容器的子项名称
src, // 目标的子项内容
copy, // 待拷贝容器的子项拷贝对象
copyIsArr, // 拷贝对象是否为数组
clone; // 需要再拷贝的内容
// 如果参数第一个布尔值的话,则判断是否需要深拓展拷贝
if (typeof target === 'boolean') {
deep = target;
// 将被拷贝值往后退一位
target = arguments[1];
// 同时被拷贝的项也往后推一位
i++;
}
// 如果目标值不是对象,而且也不是方法的话,必须初始化为对象。
if (typeof target !== 'object' && isType(target, 'Function')) {
target = {};
}
// 如果参数长度等于初始化值的话
// 待拷贝目标属于自身,同时将被拷贝内容序号往前推一位。
if (i === lens) {
target = this;
i--;
}
// 开始正式拷贝
for (; i < lens; i++) {
// 将被拷贝对象赋值给otpions,同时必须保证对象不能为null
if ((options = arguments[i]) != null) {
// 循环options对象赋值给target
for (name in options) {
src = target[name];
copy = options[name];
// 如果拷贝对象和被拷贝的相等 则跳过该阶段的迭代,走一轮
if (target === copy) {
continue;
}
// 如果存在copy的值,且是深拷贝模式,且copy属于简单对象or属于数组对象
if (
deep &&
copy &&
isPlianObejct(copy || (copyIsArr = isType(copy, 'Array')))
) {
if (copyIsArr) {
// 如果为数组对象,则判断src是否为数组对象,
// 如果是则赋值,不是则初始化数组[]
clone = src && isType(src, 'Array') ? src : [];
} else {
// 同理
// 如果src为简单对象,则判断src是否为数组对象,
// 如果是则赋值,不是则初始化数组[]
clone = src && isPlianObejct(obj) ? src : {};
}
// 递归该方法,不断往里面拷贝拓展
target[name] = extend(deep, clone, copy);
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
}
示例
let a = { name: 'Kisn' };
let b = {
age: 25,
job: {
name: 'f2e'
},
love: ['code', 'js']
};
let c;
extends(true,c,a,b)
结果
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。