【问题标题】:Why is a function within an object constructor altering all objects previously created by that constructor?为什么对象构造函数中的函数会更改该构造函数先前创建的所有对象?
【发布时间】:2013-05-22 21:16:25
【问题描述】:

我在对象构造函数中有一个函数,它改变了该构造函数创建的所有对象。我不确定为什么。有人可以看看我的代码并告诉我我缺少什么吗?

简要说明正在发生的事情:

警告!通读代码可能比试图理解我的描述更容易

我创建了两个新数组。第一个称为foos,它将是一个foo 对象数组,每个对象都包含一个bar 对象数组。第二个称为bars,它是一个包含所有bar 对象的数组,这些对象可以添加到foos.foo.bars 数组中。

当使用foo 对象构造函数创建一个新的foo 对象时,它会被赋予两个参数(aBars,bBars)。 aBars 是包含在 foo 对象中的所有 bar 对象的数组。 bBars 是一个包含所有 bar 对象的数组,这些对象在某种程度上被认为是“特殊的”。在构造函数中,有一个函数贯穿bars 数组中的每个对象,如果它的名称值与aBars 参数中的字符串匹配,则将其添加到foo.bars 数组中。如果它的名称值与bBars 参数中的字符串匹配,则将其属性bBar 设置为true,否则设置为false。

我遇到的问题是,在第二个 foo 对象构造函数中,当 bar 对象将 bBar 设置为 true 或 false 时,它​​还会更改所有其他 foo.bars 对象中该对象中的该值。

我意识到这可能很难理解。抱歉,今天结束了。


找到我自己的答案!

我刚刚意识到问题所在。 foos[0].bars[4]foos[1].bars[3] 不是单独的对象,它们只是指向同一个对象的两个不同变量。因此,当一个更改时,更改都会显示在两者上。哇,我不敢相信我花了这么多时间来解决这个问题,而答案是关于 javascript 如何工作的基本事实,这是我刚开始时学到的。

好的,新问题:

如何更改此代码以创建对象的副本,而不仅仅是指向原始对象?这不是我以前必须做的事情。


谢谢

jsfiddle

JS:

var foos = new Array();
var bars = new Array();

function foo(aBars,bBars) {
    var $this = this;
    this.aBars = aBars;
    this.bars = new Array();
    bars.forEach(function(e,i) {
        if ($this.aBars.lastIndexOf(e.barName) > -1) {
            $this.bars.push(e);
            if (bBars.lastIndexOf(e.barName) > -1) {
                $this.bars[$this.bars.length-1].bBar = true;
            } else {
                $this.bars[$this.bars.length-1].bBar = false;
            }
        }
    });
}
function bar(name) {
    this.barName = name;
}

bars.push(new bar('l'));
bars.push(new bar('m'));
bars.push(new bar('n'));
bars.push(new bar('o'));
bars.push(new bar('p'));

foos.push(new foo(['l','m','n','o','p'],['n','p']));
foos.push(new foo(['l','n','o'],['n','o']));

console.log(foos);

【问题讨论】:

  • 这段代码有很多问题......但有几点:不要使用new Array,使用[]。总是大写构造。公约事项。每当您在构造函数中定义函数时,请考虑prototype,最重要的是:阅读thisforEach 回调的调用上下文
  • 为什么我不能使用new Array?我已经阅读并被告知,在定义一个空数组时 new Array 更好。是的,我通常大写构造,这更像是一个错字,因为试图在 jsfiddle 中快速重新创建问题。我怎么没有“思考原型”?
  • 你在哪里教的new Array比较好?数组构造函数is slower,它严重超载(new Array(10) vs new Array('10')),当你写bars.foreach(function时你没有考虑prototype,这与this.bars不同,并为您创建的每个实例构造一个 foreach 回调。最好把它变成原型方法......
  • 感谢您的澄清。我将开始使用[]bars.foreach() 正在为全局变量 bars 中的每个对象运行函数。 this.bars 将针对一个空数组。 bars.foreach 回调的要点是充当过滤器,仅将所需对象从全局变量添加到这个新数组。我在这里错过了你的观点吗?我明白你关于使用原型方法的观点,但我肯定忽略了这一点。谢谢您的帮助。我对这方面还比较陌生,只要能得到指导,我就很感激。
  • 好吧,让构造函数(或任何函数,就此而言)的行为依赖于 global 变量并不是我所说的好主意。特别是如果该全局变量与属性具有相同的名称。如果我在工作中看到这段代码,我会假设有人犯了一个错误,并对他使用全局变量大喊大叫。我建议您查看closures,以便您可以将bars 数组“绑定” 到构造函数。

标签: javascript object constructor


【解决方案1】:

实现这一目标的唯一方法是替换这一行

$this.bars.push(e); 

在你的 'foo'-constructor 中使用这个:

$this.bars.push(new bar(e.barName));

在 javascript 中克隆对象只能通过复制它们的属性来实现。

【讨论】:

    猜你喜欢
    • 2013-11-10
    • 2017-05-12
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 2013-10-20
    • 2021-10-22
    • 1970-01-01
    相关资源
    最近更新 更多