使用 jQuery 的 JavaScript 意外对象行为

JavaScript unexpected object behavior with jQuery

本文关键字:对象 意外 JavaScript jQuery 使用      更新时间:2023-09-26

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

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

正如我所期望的那样,这会在两个<div>元素中的每一个元素中产生一个<input>元素。

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

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

您正在显式创建 1 个输入:

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

。但是当您尝试将其附加到多个div 时隐式克隆它

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

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

下面是一个 jsFiddle 示例,该示例在调用 insert() 时递增一个 i 变量,并将其添加为输入的值。请注意,它始终设置为 0

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

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


编辑:

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

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

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

这是另一个 jsFiddle 示例,它向原始属性添加一个自定义属性,然后在每个insert()之后使用该自定义属性的元素旁边添加一些文本。在第二个div中,文本始终添加到该原件旁边。

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

如果以这种方式选择的元素插入到其他位置,它将被移动到目标中(而不是克隆(

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

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

在代码结束时,第一个div 包含两个输入,但第二个div 仅包含最新的输入,因为每个输入都已从上一个div 中删除。

http://jsfiddle.net/hePwM/

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

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

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

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

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

奇怪的行为是由于您在不应该使用的地方使用了 JQuery 集合。 它最初是如何工作的超出了我的技能范围。

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

试试 each((:

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