javascript 模块扩展嵌套对象
javascript module extend nested object
我正在做一个带有默认选项对象的小 JavaScript 模块,它看起来像这样:
var myModule = function() {
// Define option defaults
var defaults = {
foo: 'bar',
fooObject: {
option1: [],
option2:true,
option3: false,
}
}
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(defaults, arguments[0]);
}
}
所以当我这样调用我的模块时
var moduleInstance = new myModule({
foo: 'some value',
fooObject: {
option1: [1, 2, 3]
}
});
moduleInstance.options.foo; //will retrurn an array [1, 2, 3]
但是
moduleInstance.options.fooObject; //will only contain option1
我理解为什么在创建对象时没有定义 option2 和 option3,但我不知道如何解决这个问题。
我在另一个框架上使用 jQuery 找到的所有片段。
编辑:
抱歉这里缺少 extendDefault() 它是:
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
编辑:可能的解决方法
我最后是这样做的
http://jsfiddle.net/optionsit/sgmme5dy/
在检查 hasOwnProperty 的循环中
我把那个 if 语句
if(typeof properties[property] === 'object' && typeof properties[property].nodeType === 'undefined' )
所以我可以检查该值是否是对象而不是 DOM 元素(因为我也在顶级值中传递了一些 DOM 元素)
如果它是一个 JavaScript 对象,我会遍历它的子对象以查看它们是否已设置在参数中,并且仅在已设置时才替换它们。
它可能不是很漂亮,但它适用于我的用例,如果您有更好的选择,请随时发表评论我会接受更漂亮的答案。
感谢您的帮助
您的代码替换了整个 fooObject
,这可能不是您的本意。根据您的要求,有多种方法可以解决此问题。例如,您可以添加一个额外的方法,以防您想要 "Add" 新事物到 fooObject
而不是使用 "constructor".
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
var myModule = function () {
// Define option defaults
var defaults = {
foo: 'bar',
fooObject: {
option1: [],
option2: true,
option3: false,
}
}
this.options = extendDefaults({}, defaults);
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(this.options, arguments[0]);
}
}
var moduleInstance = new myModule({
foo: 'some value',
});
moduleInstance.options.fooObject.option1 = [1, 2, 3];
console.log(moduleInstance.options.fooObject);
console.log(moduleInstance.options.foo);
你只需要递归地调用你的extendDefaults
:
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
if (typeof properties[property] === 'object' && typeof properties[property].nodeType === 'undefined') {
extendDefaults(source[property], properties[property]);
} else {
source[property] = properties[property];
}
}
}
return source;
}
这是更新后的 fiddle:http://jsfiddle.net/sgmme5dy/3/
请记住,此函数将中断 null
值和 Date
属性,因为:typeof null === 'object'
和 typeof new Date === 'object'
.
要处理这些,只需将其添加到 if:
if (typeof properties[property] === 'object' && properties[property] !== null && !(properties[property] instanceof Date) && typeof properties[property].nodeType === 'undefined')
编辑:完全忘记了数组,它们也是 typeof object
。最后,我认为最好只依赖现有的许多 extend
函数之一。例如,如果您使用 jQuery,则可以使用 $.extend, or of you use lodash/underscorejs you can use _.assign. If you don't use or don't want to use any of these libraries, then there are small standalone libraries also, like this one: node-deep-extend
我正在做一个带有默认选项对象的小 JavaScript 模块,它看起来像这样:
var myModule = function() {
// Define option defaults
var defaults = {
foo: 'bar',
fooObject: {
option1: [],
option2:true,
option3: false,
}
}
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(defaults, arguments[0]);
}
}
所以当我这样调用我的模块时
var moduleInstance = new myModule({
foo: 'some value',
fooObject: {
option1: [1, 2, 3]
}
});
moduleInstance.options.foo; //will retrurn an array [1, 2, 3]
但是
moduleInstance.options.fooObject; //will only contain option1
我理解为什么在创建对象时没有定义 option2 和 option3,但我不知道如何解决这个问题。 我在另一个框架上使用 jQuery 找到的所有片段。
编辑:
抱歉这里缺少 extendDefault() 它是:
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
编辑:可能的解决方法
我最后是这样做的 http://jsfiddle.net/optionsit/sgmme5dy/
在检查 hasOwnProperty 的循环中
我把那个 if 语句
if(typeof properties[property] === 'object' && typeof properties[property].nodeType === 'undefined' )
所以我可以检查该值是否是对象而不是 DOM 元素(因为我也在顶级值中传递了一些 DOM 元素)
如果它是一个 JavaScript 对象,我会遍历它的子对象以查看它们是否已设置在参数中,并且仅在已设置时才替换它们。
它可能不是很漂亮,但它适用于我的用例,如果您有更好的选择,请随时发表评论我会接受更漂亮的答案。
感谢您的帮助
您的代码替换了整个 fooObject
,这可能不是您的本意。根据您的要求,有多种方法可以解决此问题。例如,您可以添加一个额外的方法,以防您想要 "Add" 新事物到 fooObject
而不是使用 "constructor".
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
var myModule = function () {
// Define option defaults
var defaults = {
foo: 'bar',
fooObject: {
option1: [],
option2: true,
option3: false,
}
}
this.options = extendDefaults({}, defaults);
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(this.options, arguments[0]);
}
}
var moduleInstance = new myModule({
foo: 'some value',
});
moduleInstance.options.fooObject.option1 = [1, 2, 3];
console.log(moduleInstance.options.fooObject);
console.log(moduleInstance.options.foo);
你只需要递归地调用你的extendDefaults
:
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
if (typeof properties[property] === 'object' && typeof properties[property].nodeType === 'undefined') {
extendDefaults(source[property], properties[property]);
} else {
source[property] = properties[property];
}
}
}
return source;
}
这是更新后的 fiddle:http://jsfiddle.net/sgmme5dy/3/
请记住,此函数将中断 null
值和 Date
属性,因为:typeof null === 'object'
和 typeof new Date === 'object'
.
要处理这些,只需将其添加到 if:
if (typeof properties[property] === 'object' && properties[property] !== null && !(properties[property] instanceof Date) && typeof properties[property].nodeType === 'undefined')
编辑:完全忘记了数组,它们也是 typeof object
。最后,我认为最好只依赖现有的许多 extend
函数之一。例如,如果您使用 jQuery,则可以使用 $.extend, or of you use lodash/underscorejs you can use _.assign. If you don't use or don't want to use any of these libraries, then there are small standalone libraries also, like this one: node-deep-extend