使用jQuery的JavaScript意外对象行为

时间:2011-08-02 19:44:43

标签: javascript jquery

我有两个<div>元素,以及以下JavaScript代码:

var myObject = {
    $input: $('<input />'),
    insert: function () {
        $('div').append(this.$input);
        $('div').append(' ');
    }
};

myObject.insert();

正如我所料,这会在两个<input>元素的每个元素中生成一个<div>元素。

现在,当我创建myObject的新实例并再次调用insert()时,我将期待4 <input>个元素,每个<div>两个元素。奇怪的是,我只获得3个<input>元素!

请参阅此处的示例代码: http://jsfiddle.net/FNEax/

5 个答案:

答案 0 :(得分:12)

您明确创建了1个输入:

$input: $('<input />',{value:i}),

...但是当你尝试将它附加到多个div时隐式克隆它

// 2 divs
$('div').append(this.$input);

然后Object.create不会创建新的$input,所以在第二次传递时,它会将第二个div(实际上是原始的)的输入附加(移动)到第一个div,然后隐式克隆填充第二个。

每当调用i时,

Here's a jsFiddle example会增加insert()变量,并将其作为输入值添加。请注意,它始终设置为0

我还修改了它以将字符串传递给insert,这样您就可以看到每个输入来自哪个调用。

第二次调用的两个输入仍然将字符串传递给第一个调用。


编辑:

我在解释中间翻了一下,但概念是一样的。

当调用第二个insert()时,首先会创建原始克隆并添加到第一个div,然后将原始内容附加到第二个div(其中已经存在)是)。

jQuery首先制作克隆,然后追加原始的最后一个。

Here's another jsFiddle example将自定义属性添加到原始属性,然后在每个insert()之后在该元素旁边添加一些文本。文本始终在第二个div中的原始文本旁边添加。

答案 1 :(得分:3)

这就是发生的事情。来自jQuery文档:

  

如果以这种方式选择的元素插入其他地方,它将被移动到目标(未克隆)

     

但是,如果有多个目标元素,则会在第一个目标元素之后为每个目标创建插入元素的克隆副本。

所以第一次,因为你的输入不在DOM的任何地方,它被克隆并插入到两个div中。但是,第二次调用它时,它会从第二个div中删除,然后被克隆并添加回两个div中。

在代码的末尾,第一个div包含两个输入,但第二个div只包含最近的输入,因为每个输入都从最后一个div中删除。

http://jsfiddle.net/hePwM/

答案 2 :(得分:2)

一旦元素被插入到DOM中,另一个.append()调用它作为附加内容会使它在DOM内移动(docs)。您的代码创建了一个带有单个输入的jQuery集合,该输入尚未附加到DOM。因此,第一次调用insert()会将其附加到每个(使用jQ内部的克隆或复制机制)。

然而,在第二次调用中,this.$input引用了DOM中已有的内容(由于第一次调用)。在内部,jQuery是each - DIV的集合,并附加存在于this.$input内部的输入。所以它添加它,移动它。

主要问题是你一遍又一遍地重新添加相同的输入。请记住,JavaScript通常引用现有对象而不是创建新对象。相同的输入元素不断被重新引用。

如果你想要一个方法来为每个DIV添加一个输入,你应该简单地将输入标记传递给append:

$( 'div' ).append( '<input />' );

答案 3 :(得分:2)

奇怪的行为是因为您使用的是JQuery集合,而您不应该这样做。它首先如何起作用超出了我的技能。

var myObject = {
input: '<input />',
insert: function () {
    $('div').append(this.input);
    //$('div').append(' ');
}
};

答案 4 :(得分:0)

尝试each()

var myObject = {
    insert: function () {
        $('div').each(function(index) {
            $(this).append($('<input />'));
            $(this).append(' ');
        });
    }
};

myObject.insert();
myObject.insert();