javascript模块扩展嵌套对象

时间:2015-08-11 09:17:59

标签: javascript object module

我正在做一个带有默认选项对象的小型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对象,我会通过它的子进行迭代,看看它们是否在参数中设置并仅在它们被替换时替换它们。

它可能不是很漂亮,但它适用于我的用例,如果你有更好的选择,请随时评论我会接受更漂亮的答案。

感谢您的帮助

2 个答案:

答案 0 :(得分:1)

您的代码替换了可能不是您的意图的整个fooObject。根据您的要求,有多种方法可以解决这个问题。例如,你可以添加一个额外的方法,以防你想要"添加" fooObject的新内容,而不是使用"构造函数"。

 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);

https://jsfiddle.net/w5ut28es/

答案 1 :(得分:1)

您只需递归调用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;
}

这是一个更新的小提琴: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')

编辑:完全忘记了数组,它们也是object的类型。最后,我认为最好只依靠现有的extend个函数中的一个。例如,如果你使用jQuery,你可以使用$.extend,或者你使用lodash / underscorejs你可以使用_.assign。如果您不使用或不想使用任何这些库,那么还有一些小型独立库,如下所示:node-deep-extend