使用lodash的extend方法扩展JS对象实例会导致奇怪的结果

时间:2016-04-01 23:07:47

标签: javascript arrays object lodash

我有一个JS类,它有一些默认属性。我希望能够传入一个options对象来覆盖默认值以及一些未默认的其他对象。我在构造函数中使用lodash的extend方法来完成此任务。

其中一个默认属性是数组。如果我实例化第一个实例并将新值推入数组,那么当我实例化第二个对象时,默认数组包含我推入第一个实例的对象。

以此代码为例......

MyClass = (function() {
  var defaults = {
    myArr: [],
    myProp: 'I\'m a default value'
  };

  function MyClass(options) {
    // console.log(defaults)
    if(typeof options === 'object') {
      return _.extend(this, defaults, options);
    }
    else {
      return _.extend(this, defaults);
    }
  }

  return MyClass;
})();

var myObj = new MyClass({foo: 'bar'})
myObj.myArr.push('baz')
var mySecondObj = new MyClass();
console.log(mySecondObj) // MyClass {myArr: Array[1]}

我希望mySecondObj.myArr是一个空数组。

当我将值推入myObj.myArrdefaults.myArr以某种方式被更改并用于后续的类实例时,该怎么办?

2 个答案:

答案 0 :(得分:3)

将对象属性从defaults合并到this_.extend时,您只需创建对该数组的引用。因此,当更新一个实例中的数组引用时,所有引用都会反映该更改。

您可以克隆该对象以解决此问题:

_.cloneDeep(defaults)

DEMO

或使用更简单的构造函数:

function MyClass(options) {
  var defaults = {
    myArr: [],
    myProp: 'I\'m a default value'
  }
  if (typeof options === 'object') {
    _.extend(this, defaults, options);
  } else {
    _.extend(this, defaults);
  }
}

DEMO

答案 1 :(得分:1)

简单说明:您创建了closure

在自执行函数中创建另一个函数,您创建的函数从它的父自执行函数继承defaults,当您将函数返回到MyClass时,任何对象创建都将具有这些默认值(the defaults object)的引用相同,每次创建类时都没有创建defaults对象,这就是为什么它总是相同的。