0

似乎 jQuery 数据可以将数据链接到多个元素。在下面的示例中,两个元素都获得了两个属性,尽管看起来它应该只影响#one元素。

我认为这是 jQuery 中的预期行为,因为它正在更改对象?

<div id="one" class="thing"></div>
<div id="two" class="thing"></div>
<div id="three" class="thing"></div>
<script>
jQuery(function($) {
    $('.thing').data('obj',{a:'a'});

    $('#one').data('obj',$.extend($('#one').data('obj'),{one:'one'}));

    //Display:
    for (i in $('#one').data('obj')) {
        alert(i+' in obj.');
    }
    for (i in $('#two').data('obj')) {
        alert(i+' in obj.');
    }
})
</script>

JSF中:

http://jsfiddle.net/qFZ6y/

我知道用 .each() 函数初始化来设置单个数据可以解决这个问题,但这会被认为是 javascript 或 jQuery 中的错误吗?

4

3 回答 3

2

这实际上是您使用$.extend文档结果:

请记住,目标对象(第一个参数)将被修改,并且也将从 $.extend() 返回。但是,如果您想保留两个原始对象,可以通过传递一个空对象作为目标来实现:

var object = $.extend({}, object1, object2);

从您的原始代码中,唯一需要的更改是:

jQuery(function($) {
    $('.thing').data('obj',{a:'a'});

    $('#one').data('obj',$.extend({}, $('#one').data('obj'),{one:'one'}));

    //Display:
    for (i in $('#one').data('obj')) {
        alert(i+' in obj.');
    }
    for (i in $('#two').data('obj')) {
        alert(i+' in obj.');
    }
})

在此处查看更改:http: //jsfiddle.net/potatosalad/qFZ6y/2/

更长的解释

对于以下代码块:

var a = {};
var b = {};
var c = {};

var debug = function() {
  console.log("  a.obj: %s", JSON.stringify($(a).data('obj')));
  console.log("  b.obj: %s", JSON.stringify($(b).data('obj')));
  console.log("  c.obj: %s", JSON.stringify($(c).data('obj')));
};

// a, b, and c all have the same obj
$([a, b, c]).data('obj', {x: true});
console.log("-- test 1 --");
console.log("a.obj = b.obj = c.obj = {\"x\":true}");
debug();

// extending the obj of any of them will affect all others
$(a).data('obj', $.extend($(a).data('obj'), {y: true}));
console.log("-- test 2 --");
console.log("$.extend(a.obj, {\"y\":true})");
debug();

// b.obj is now a different obj from a and c
$(b).data('obj', $.extend({}, $(b).data('obj'), {z: true}));
console.log("-- test 3 --");
console.log("$.extend({}, b.obj, {\"z\":true})");
debug();

// c.obj is still affected by changes to a.obj (b.obj is not)
$(a).data('obj').m = true
console.log("-- test 4 --");
console.log("a.obj.m = true");
debug();

// c.obj is now different from a.obj and b.obj
$(c).data('obj', {r: true})
console.log("-- test 5 --");
console.log("c.obj = {\"r\":true}");
debug();

// a.obj changes do not affect b.obj or c.obj
$(a).data('obj', $.extend($(a).data('obj'), {s: true}));
console.log("-- test 6 --");
console.log("$.extend(a.obj, {\"s\":true})");
debug();

结果如下:

-- test 1 --
a.obj = b.obj = c.obj = {"x":true}
  a.obj: {"x":true}
  b.obj: {"x":true}
  c.obj: {"x":true}
-- test 2 --
$.extend(a.obj, {"y":true})
  a.obj: {"x":true,"y":true}
  b.obj: {"x":true,"y":true}
  c.obj: {"x":true,"y":true}
-- test 3 --
$.extend({}, b.obj, {"z":true})
  a.obj: {"x":true,"y":true}
  b.obj: {"x":true,"y":true,"z":true}
  c.obj: {"x":true,"y":true}
-- test 4 --
a.obj.m = true
  a.obj: {"x":true,"y":true,"m":true}
  b.obj: {"x":true,"y":true,"z":true}
  c.obj: {"x":true,"y":true,"m":true}
-- test 5 --
c.obj = {"r":true}
  a.obj: {"x":true,"y":true,"m":true}
  b.obj: {"x":true,"y":true,"z":true}
  c.obj: {"r":true}
-- test 6 --
$.extend(a.obj, {"s":true})
  a.obj: {"x":true,"y":true,"m":true,"s":true}
  b.obj: {"x":true,"y":true,"z":true}
  c.obj: {"r":true}
于 2013-04-25T01:45:09.200 回答
2

正如您所提到的,这是您使用相同对象这一事实的副作用。因此,与其说它正在更改与选择器不匹配的事物的数据,不如说它正在为您碰巧设置为共享的对象设置一个值。

如果您不想共享数据,则需要使用.each循环单独设置数据。

于 2013-04-25T01:39:24.567 回答
2

这绝不是一个错误。

如果你有这个,你的代码会做同样的事情:

var a = {a:'a'}, b = a;
b.c = "derp";
alert(a.c); // derp

这是因为对象是通过引用而不是值传递的。如您所述,要获取单个对象,您应该使用.each循环。

于 2013-04-25T01:39:47.050 回答