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

https://jsfiddle.net/w5ut28es/

你只需要递归地调用你的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