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

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

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

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

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

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

并将其添加到每个元素:选择器中的$(this).data('prodigal', options) 。 当我调用另一个函数时,我得到每个元素的正确width值( 500600为另一个), click元素时open

但是,如果我这样做:

 options = $.extend(options, opts); 

对于两个选择器,尽管被单独调用,我得到600 。 我在open函数中通过执行测试:

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

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

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

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

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

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

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

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

这是关于jsFiddle的测试用例 。

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

我在PHP中看到了一个关于内存管理写入场景的副本: 什么是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); 

这是certificate,因为如果您将小提琴中的这一行更改为:

 $(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,有一些事情会引起人们的兴趣。 一个事实是,为变量分配布尔值或字符串会生成该值的副本,而将数组或对象分配给变量则会引用该值。

这完全解释了我的问题。