对象的扩展
2017-05-24 本文已影响0人
狒狒神
<pre>简而言之,对象的扩展就是通过类似于<strong>extend</strong>的方法,将对象的功能进行方便的管理(删除或者添加或者是修改)。
</pre>
我们能够轻松想到的方法是
let extend = (destination, source) => {
let i;
for (i in source) {
destination[i] = source
}
}
首先,在IE中<code>valueOf toString</code>等方法使用<code>for in</code>循环无法被遍历出来,那么在司徒正美的<code>mass Framework</code>中的<code>mix</code>方法是如何实现的呢?
function mix(receiver, supplier) {
var args = [].slice.call(arguments),
i = 1,
key, //如果最后参数是布尔,判定是否覆写同名属性
ride = typeof args[args.length - 1] === "boolean" ? args.pop() : true;
if (args.length === 1) { //处理$.mix(hash)的情形
receiver = !this.window ? this : {};
i = 0;
}
while ((supplier = args[i++])) { //允许合并多个对象
for (key in supplier) { //允许对象糅杂,用户保证都是对象
if (hasOwn.call(supplier, key) && (ride || !(key in receiver))) {
receiver[key] = supplier[key];
}
}
}
return receiver;
}
}
其实呢,这种类似于对象合并的方法,在es6中已经有了相应的原生方法即Object.assign(target, source1, source2)
,并且在各大浏览器已经得到广泛的支持。
但是,不得不注意的是这个方法只是对象的浅拷贝,即获取的是源对象的引用,而且如果存在同名属性,后面的属性会覆盖前面的属性(这一点在司徒的mix
方法中已经做过考虑),那么我们需要一个方法来进行深拷贝的对象合并。
于是我做了如下的尝试:
function assign (target, source, boolean) {
let args = [].slice.call(arguments),
i = 1,
key, //如果最后参数是布尔,判定是否覆写同名属性
ride = typeof args[args.length - 1] === "boolean" ? args.pop() : true;
let getSameObj = obj => {
if (typeof obj !== "object") {
return obj;
}
let s = {};
if (obj.constructor != Array) {
s = {};
Object.getOwnPropertyNames(obj).forEach(item => {
s[item] = getSameObj(obj[item])
}) //遍历包括不可枚举的属性
}
return s;
}
if (args.length <= 1) {
return target || {}
}
while ((source = getSameObj(args[i++]))) { //允许合并多个对象,并使用的是深拷贝
Object.getOwnPropertyNames(source).forEach(key => {
if (source.hasOwnProperty(key) && (ride || !(key in target))) {
target[key] = source[key];
}
})
}
return target
}