Difference in $.extend calls in a plugin?

你。 提交于 2019-12-24 07:59:21

问题


I believe this question relates to this: How does the init function work in plugins? and whoever can answer this can probably answer that.

I noticed something about jQuery, if I call my plugin like:

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

And then, in my init function I extend with:

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

and add that to each element: $(this).data('prodigal', options) in the selector. I get the correct width value for each element (500 for one and 600 for the other) later on when I call another function, open on the click of the element.

However if I do:

options = $.extend(options, opts);

For both selectors, despite being called separately, I get 600. I test this by doing, in my open function:

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

I know that not extending to an empty object will override the object for that selector/global object but why is this happening on the data of each selector?


回答1:


First of all, it's an object, not an array. And you most likely don't want to extend the preexisting object, but instead create a new one that is based on the defaults, and then override those with the passed options, something like this:

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

What $.extend does is that it will extend the first argument (an array or an object) with the rest of the arguments. Passing a preexisting object as the first argument will therefor not create a clone, but change the original.

In the example above, by passing a new object ({}) we instead create a clone of the second argument that we then override with the third.

Changing this would solve a lot, but you can still run into race-conditions since it will still share the same options object between instances. So, what if I want to change an option for just one or two of those instances?

The solution is simple, just move that line into the .each loop and every instance of your plugin will have its own options object.

Here's a test case on jsFiddle.




回答2:


Even though @Marcus' answer is a good one and it shows a good setup to plugins that will actually avoid this confusion I thought I would place this answer because it just answers the question a little better.

I am witnessing, like in PHP, a copy on write scenario for memory management here: What is copy-on-write? whereby my init function, as displayed in this fiddle: http://jsfiddle.net/Sammaye/65XLy/1 suffers from the static options object being referenced to each of the calls. So both of:

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

Reference the same position in memory for the options object in the plugin since the data assignment is not copy on write safe:

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

This is proven since if you change this line in the fiddle to:

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

It actually works the same as var options = $.extend({}, options, opts); whereby it does copy to a new empty object on extend which in copy on write would trigger a copy.

That is why I am seeing this, because the data in each of the elements is actually a reference to the static objects (plugins) options object.

As an added note I actually found this soon after posting this answer: http://my.opera.com/GreyWyvern/blog/show.dml/1725165 whereby the author states:

There are a few things that trip people up with regards to Javascript. One is the fact that assigning a boolean or string to a variable makes a copy of that value, while assigning an array or an object to a variable makes a reference to the value.

Which explains my problem perfectly.



来源:https://stackoverflow.com/questions/13797815/difference-in-extend-calls-in-a-plugin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!