插件中$ .extend调用的差异?

时间:2012-12-10 09:04:31

标签: jquery jquery-plugins

我相信这个问题与此有关:How does the init function work in plugins?无论谁能回答这个问题,都可以回答这个问题。

我注意到jQuery的一些内容,如果我将我的插件称为:

$('.view_title_images').prodigal({width: 500});
$('.glglg').prodigal({ width: 600 });

然后,在我的init函数中,我延伸:

options = $.extend({}, options, opts); 

并将其添加到选择器中的每个元素:$(this).data('prodigal', options)。当我在{{1}上调用另一个函数width时,我会得到每个元素的正确500值(一个600和另一个open)元素。

但是,如果我这样做:

click

对于两个选择器,尽管被单独调用,但我得到options = $.extend(options, opts); 。我在600函数中执行此操作:

open

我知道不扩展到空对象会覆盖该选择器/全局对象的对象,但为什么会在每个选择器的console.log($(this).data('prodigal')); 上发生这种情况?

2 个答案:

答案 0 :(得分:1)

首先,它是一个对象,而不是一个数组。并且您很可能不想扩展预先存在的对象,而是创建一个基于默认值的新对象,然后使用传递的选项覆盖那些,如下所示:

options = $.extend({}, defaults, opts);

$.extend所做的是它将使用其余参数扩展第一个参数(数组或对象)。将预先存在的对象作为第一个参数传递将不会创建克隆,而是更改原始对象。

在上面的示例中,通过传递一个新对象({}),我们改为创建第二个参数的克隆,然后我们用第三个参数覆盖。

更改此内容会解决很多问题,但您仍然可以遇到竞争条件,因为它仍然会在实例之间共享相同的选项对象。那么,如果我只想改变其中一个或两个实例的选项呢?

解决方案很简单,只需将该行移到.each循环中,插件的每个实例都有自己的选项对象。

这是test case on jsFiddle

答案 1 :(得分:0)

即使@Marcus的答案很好,它显示了一个很好的插件设置,实际上可以避免这种混乱,我想我会把这个答案放在一边,因为它只是更好地回答了这个问题。

我正在见证,就像在PHP中一样,这里有关于内存管理的写入方案的副本:What is copy-on-write?我的init函数,如此小提琴中显示的那样:http://jsfiddle.net/Sammaye/65XLy/1会受到被引用的静态选项对象的影响每个电话。所以两者:

$('.view_title_images').prodigal({width: 500});
$('.glglg').prodigal({ width: 600 });

在内存中为插件中的options对象引用相同的位置,因为数据赋值不是写入安全的副本:

$(this).data('prodigal', options).on('click', open);

这证明是因为如果你在小提琴中改变这一行:

$(this).data('prodigal', $.extend(options, opts)).on('click', open);

它实际上与var options = $.extend({}, options, opts);的作用相同,它会复制到扩展上的新空对象,在写入时复制会触发副本。

这就是我看到这个的原因,因为每个元素中的data实际上是对静态对象(插件)options对象的引用。

作为补充说明,我在发布此答案后很快就发现了这一点:http://my.opera.com/GreyWyvern/blog/show.dml/1725165作者声明:

  

有一些事情可以让人们了解Javascript。一个事实是,为变量分配布尔值或字符串会生成该值的副本,而将数组或对象分配给变量则会引用该值。

这完全解释了我的问题。