我开始寻找并理解在Vanilla JS中合并对象的好方法。我对函数的要求非常简单(借鉴here):
深入合并两个对象x
和y
,使用x
和y
中的元素返回一个新的合并对象。
如果x
和y
同时存在同一个键的元素,则y
中的值将显示在结果中。
合并是不可变的,因此x
和y
都不会被修改。
我遇到this文章似乎提供了一个很好的解决方案。在完成代码并理解它(大部分)之后,我将其缩短为以下内容:
var extend = function() {
var extended = {};
var length = arguments.length;
// Merge the object into the extended object
var merge = function(obj) {
for (var prop in obj) {
//Check if a property is an object and another layer of merging is required
if (Object.prototype.toString.call(obj[prop]) === '[object Object]') {
extended[prop] = extend(true, extended[prop], obj[prop]);
} else {
extended[prop] = obj[prop];
}
}
};
// Loop through each object and conduct a merge
while (length--) {
var obj = arguments[length];
merge(obj);
}
return extended;
};
从原始解决方案中,我删除了深度合并的检查,因为我希望默认深度合并,并且检查当前合并的属性值之前存在的这一行是否为对象:
if ( Object.prototype.hasOwnProperty.call( obj, prop ) )
我不理解这一行 - 我们为什么要检查当前循环其属性的对象是否具有当前循环中的属性?我觉得我错过了什么。
这就是它。有什么情况下这个功能不能满足我的要求吗?或者以其他方式中断执行?谢谢。
答案 0 :(得分:2)
if ( Object.prototype.hasOwnProperty.call( obj, prop ) )
我不理解这一行 - 我们为什么要检查当前循环其属性的对象是否具有当前循环的属性?
因为for-in
循环访问对象的所有可枚举属性,包括它从其原型继承的属性。是否要复制继承的属性取决于extend
函数的用例。显然在原始代码中,他们不想。
显示差异的示例:
var name;
var p = {inherited: "property"};
// Create an object using p as its prototype
var o = Object.create(p);
o.own = "property";
console.log("Without check");
for (name in o) {
console.log("- " + name);
}
console.log("With check");
for (name in o) {
if (Object.prototype.hasOwnProperty.call(o, name)) {
console.log("- " + name);
}
}