JavaScript 相当于 jQuery 的扩展方法
JavaScript equivalent of jQuery's extend method
>Background
我有一个将config
对象作为参数的函数。 在函数中,我也有default
对象。 其中每个对象都包含属性,这些属性实质上用作函数中其余代码的设置。 为了防止必须在config
对象中指定所有设置,我使用 jQuery 的 extend
方法来填充一个新对象,如果使用 default
对象中的任何默认值(如果未在config
对象中指定),则settings
var config = {key1: value1};
var default = {key1: default1, key2: default2, key 3: default 3};
var settings = $.extend(default, config);
//resulting properties of settings:
settings = {key1: value1, key2: default2, key 3: default 3};
问题
这很好用,但我想在不需要 jQuery 的情况下重现此功能。 有没有一种同样优雅(或接近)的方法可以用普通的 javascript 来做到这一点?
编辑:非重复理由
这个问题不是"如何动态合并两个 JavaScript 对象的属性?"问题的副本。而这个问题只是想创建一个包含来自两个单独对象的所有键和值的对象 - 我特别想解决在两个对象共享一些但不是全部键的情况下如何执行此操作,以及哪个对象将获得优先权(默认值)在存在重复键的情况下为结果对象。更具体地说,我想解决使用jQuery的方法来实现这一点的问题,并找到一种没有jQuery的替代方法。 虽然这两个问题的许多答案重叠,但这并不意味着问题本身是相同的。
要在代码中获取结果,您需要执行以下操作:
function extend(a, b){
for(var key in b)
if(b.hasOwnProperty(key))
a[key] = b[key];
return a;
}
请记住,您在那里使用 extend 的方式将修改默认对象。 如果您不想这样做,请使用
$.extend({}, default, config)
模仿jQuery功能的更强大的解决方案如下:
function extend(){
for(var i=1; i<arguments.length; i++)
for(var key in arguments[i])
if(arguments[i].hasOwnProperty(key))
arguments[0][key] = arguments[i][key];
return arguments[0];
}
> 您可以在对象文字中使用 ECMA 2018 传播运算符...
var config = {key1: value1};
var default = {key1: default1, key2: default2, key 3: default 3};
var settings = {...default, ...config}
//resulting properties of settings:
settings = {key1: value1, key2: default2, key 3: default 3};
BabelJS 对旧版浏览器的支持
您可以使用 Object.assign。
var defaults = {key1: "default1", key2: "default2", key3: "defaults3"};
var config = {key1: "value1"};
var settings = Object.assign({}, defaults, config); // values in config override values in defaults
console.log(settings); // Object {key1: "value1", key2: "default2", key3: "defaults3"}
它将所有可枚举的自己的属性的值从一个或多个源对象复制到目标对象,并返回目标对象。
Object.assign(target, ...sources)
它适用于所有桌面浏览器,但包括 IE(但包括 Edge)。它减轻了移动支持。
在这里亲眼看看:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
关于深拷贝
但是,Object.assign 没有 jQuery 的扩展方法所具有的深度选项。
注意:您通常可以使用JSON来实现类似的效果
var config = {key1: "value1"};
var defaults = {key1: "default1", key2: "default2", keyDeep: {
kd1: "default3",
kd2: "default4"
}};
var settings = JSON.parse(JSON.stringify(Object.assign({}, defaults, config)));
console.log(settings.keyDeep); // Object {kd1: "default3", kd2: "default4"}
尝试消除jQuery依赖时提出的深度复制方法略有不同。它主要是为小而设计的,因此它可能没有人们期望的所有功能。应该完全兼容 ES5(由于使用了 Object.keys,从 IE9 开始):
function extend(obj1, obj2) {
var keys = Object.keys(obj2);
for (var i = 0; i < keys.length; i += 1) {
var val = obj2[keys[i]];
obj1[keys[i]] = ['string', 'number', 'array', 'boolean'].indexOf(typeof val) === -1 ? extend(obj1[keys[i]] || {}, val) : val;
}
return obj1;
}
您可能想知道第五行到底做了什么......如果 obj2.key 是一个对象文字(即如果它不是普通类型),我们递归调用 extend 在它上面。如果 obj1 中尚不存在具有该名称的属性,我们首先将其初始化为空对象。否则,我们只需将 obj1.key 设置为 obj2.key。
以下是我的一些摩卡/柴测试,它们应该证明常见情况在这里有效:
it('should extend a given flat object with another flat object', () => {
const obj1 = {
prop1: 'val1',
prop2: 42,
prop3: true,
prop4: 20.16,
};
const obj2 = {
prop4: 77.123,
propNew1: 'newVal1',
propNew2: 71,
};
assert.deepEqual(utils.extend(obj1, obj2), {
prop1: 'val1',
prop2: 42,
prop3: true,
prop4: 77.123,
propNew1: 'newVal1',
propNew2: 71,
});
});
it('should deep-extend a given flat object with a nested object', () => {
const obj1 = {
prop1: 'val1',
prop2: 'val2',
};
const obj2 = {
propNew1: 'newVal1',
propNew2: {
propNewDeep1: 'newDeepVal1',
propNewDeep2: 42,
propNewDeep3: true,
propNewDeep4: 20.16,
},
};
assert.deepEqual(utils.extend(obj1, obj2), {
prop1: 'val1',
prop2: 'val2',
propNew1: 'newVal1',
propNew2: {
propNewDeep1: 'newDeepVal1',
propNewDeep2: 42,
propNewDeep3: true,
propNewDeep4: 20.16,
},
});
});
it('should deep-extend a given nested object with another nested object and deep-overwrite members', () => {
const obj1 = {
prop1: 'val1',
prop2: {
propDeep1: 'deepVal1',
propDeep2: 42,
propDeep3: true,
propDeep4: {
propDeeper1: 'deeperVal1',
propDeeper2: 777,
propDeeper3: 'I will survive',
},
},
prop3: 'lone survivor',
};
const obj2 = {
prop1: 'newVal1',
prop2: {
propDeep1: 'newDeepVal1',
propDeep2: 84,
propDeep3: false,
propDeep4: {
propDeeper1: 'newDeeperVal1',
propDeeper2: 888,
},
},
};
assert.deepEqual(utils.extend(obj1, obj2), {
prop1: 'newVal1',
prop2: {
propDeep1: 'newDeepVal1',
propDeep2: 84,
propDeep3: false,
propDeep4: {
propDeeper1: 'newDeeperVal1',
propDeeper2: 888,
propDeeper3: 'I will survive',
},
},
prop3: 'lone survivor',
});
});
我很高兴对此实现的反馈或评论。提前感谢!
for
语句遍历 Object 的属性。
var settings = extend(default, config);
function extend(a, b){
var c = {};
for(var p in a)
c[p] = (b[p] == null) ? a[p] : b[p];
return c;
}
我更喜欢使用我的泛型 forEachIn 的代码,并且不会破坏第一个对象:
function forEachIn(obj, fn) {
var index = 0;
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
fn(obj[key], key, index++);
}
}
}
function extend() {
var result = {};
for (var i = 0; i < arguments.length; i++) {
forEachIn(arguments[i],
function(obj, key) {
result[key] = obj;
});
}
return result;
}
如果你真的想把东西合并到第一个对象中,你可以这样做:
obj1 = extend(obj1, obj2);
当我使用纯javascript进行开发时,它对我有很大帮助。
function extends(defaults, selfConfig){
selfConfig = JSON.parse(JSON.stringify(defaults));
for (var item in config) {
if (config.hasOwnProperty(item)) {
selfConfig[item] = config[item];
}
}
return selfConfig;
}
Ivan Kuckir的方法也可以用于创建新的对象原型:
Object.prototype.extend = function(b){
for(var key in b)
if(b.hasOwnProperty(key))
this[key] = b[key];
return this;
}
var settings = default.extend(config);
- 为什么这个扩展方法不起作用
- 下划线扩展方法和结构.js子类
- 如何使用jQuery扩展方法为元素或类选择器创建自定义插件
- 在Javascript的UserControl.aspx中添加扩展方法
- 如何在没有临时变量的情况下扩展方法(猴子补丁)
- JavaScript 相当于 jQuery 的扩展方法
- Javascript/small Jquery扩展方法,用于自动更改Z-Indexes以将元素置于所有内容之上
- 如何定义扩展方法并将其作为实例和静态方法调用
- JS扩展方法的功能
- 在 Javascript 中扩展方法
- javascript's不同的扩展方法
- jQuery扩展方法,将select元素序列化为字典
- 如何用JavaScript编写扩展方法
- 使用jQuery扩展方法将函数与对象合并,为什么'只返回s的函数
- 从Javascript Visualforce调用扩展方法
- Javascript继承扩展方法提示
- ES6模块导出-DOM元素扩展方法
- 如何在字符串原型扩展方法中使用字符串方法
- 如何在javascript中扩展方法
- 用Javascript编写一个扩展方法