1

我相信这个问题与此有关:init 函数如何在插件中工作?谁能回答这个问题,可能就可以回答这个问题。

如果我将我的插件称为:

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

然后,在我的init函数中,我扩展为:

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

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

但是,如果我这样做:

options = $.extend(options, opts);

对于这两个选择器,尽管被单独调用,我得到600. 我在我的open函数中通过这样做来测试它:

console.log($(this).data('prodigal'));

我知道不扩展到空对象将覆盖该选择器/全局对象的对象,但为什么data每个选择器都会发生这种情况?

4

2 回答 2

1

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

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

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

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

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

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

这是jsFiddle 上的一个测试用例

于 2012-12-10T09:08:24.483 回答
0

尽管@Marcus 的回答很好,并且它显示了一个很好的插件设置,实际上可以避免这种混淆,但我想我会放置这个答案,因为它只是更好地回答了这个问题。

我正在见证,就像在 PHP 中一样,这里有一个用于内存管理的写时复制场景:什么是写时复制?由此我的 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,有一些事情会让人们大吃一惊。一个事实是,将布尔值或字符串分配给变量会复制该值,而将数组或对象分配给变量会引用该值。

这完美地解释了我的问题。

于 2012-12-10T10:13:15.060 回答