【问题标题】:Extending JS object instance using lodash's extend method causes weird results使用 lodash 的 extend 方法扩展 JS 对象实例会导致奇怪的结果
【发布时间】:2016-04-01 23:07:47
【问题描述】:

我有一个具有一些默认属性的 JS 类。我希望能够传入一个选项对象来覆盖默认值以及一些未默认的附加值。我在构造函数中使用了 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.myArr 时,defaults.myArr 以某种方式被更改并用于该类的后续实例,这是怎么回事?

【问题讨论】:

    标签: javascript arrays object lodash


    【解决方案1】:

    当您将对象属性从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

    【讨论】:

    • 谢谢大家。除了关于关闭的评论之外,这一点非常有意义。
    【解决方案2】:

    简单地说:您创建了一个closure

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 2016-11-30
      • 2018-01-24
      • 1970-01-01
      • 2013-12-18
      • 1970-01-01
      • 2013-03-13
      相关资源
      最近更新 更多