jQuery OOP technique confusion
I'm looking at Jamie Talbot's technique for OOP in jQuery. I pretty much understand this for the most part, however I'm getting slightly lost when trying to understand the logic for this:
result = 开发者_StackOverflow社区$(result);
var template = result[0];
if (template)
{
for (var i in template)
{
if (typeof (template[i]) == 'function')
{
result[i] = function()
{
this.each(function()
{
this[i]();
});
};
}
}
}
I understand up to the if (typeof (template[i]) == 'function')
block, that the code is looking at each public method that is declared in the plugin, but after that it boggles me.
Is there any chance somebody could step by step me through this?
Here's Jamie's original code.
(function($) {
$.fn.encapsulatedPlugin = function(plugin, definition, objects, options) {
var result = [];
objects.each(function() {
var element = $(this);
if (!element.data(plugin)) {
// Initialise
var instance = new definition(this, options);
// Store the new functions in a validation data object.
element.data(plugin, instance);
}
result.push(element.data(plugin));
});
// We now have a set of plugin instances.
result = $(result);
// Take the public functions from the definition and make them available across the set.
var template = result[0];
if (template) {
for ( var i in template) {
if (typeof (template[i]) == 'function') {
result[i] = function() {
this.each(function() {
this[i]();
});
};
}
}
}
// Finally mix-in a convenient reference back to the objects, to allow for chaining.
result.$ = objects;
return result;
};
})(jQuery);
You're actually working off of old code there. As has been pointed out, there was some quirky behaviour in earlier drafts, (I only tested the first version with a single encapsulated function, which is why I didn't notice the rebinding issue until a day or two later - http://jamietalbot.com/2010/08/26/object-oriented-jquery-plugins-mk-2/). In particular, passing arguments wasn't possible. Regardless, there have been a couple of iterations since.
Latest code can be found on Github, which has had a number of fixes and optimisations applied.
The basic theory of operation for the bit of code you're interested in though is this:
For each public function on the plugin object, create a wrapper function that executes the public function on each element in the set. When the loop has finished iterating, there will be a result object, keyed by function name, each member of which will be a function that executes the similarly named underlying function against every element in the set.
This piece of the code in particular has been cleaned up in the GitHub version, so take a look there and see how you go.
Best,
Jamie.
That just looks broken. The same i
is bound multiple times (only a new function definition can introduce a new scope [read: free variable]). result[i]
(where i
is the current value in the loop) contains a function that, when evaluated, will "see" the last value of i
(from the loop) when it is invoked.
(Without even trying it) I claim it doesn't work as advertised.
A "corrected" version would be:
result[i] = (function (_i) {
return function() {
this.each(function() {
this[_i]();
});
};
}(i));
Happy coding :)
I was trying to explain the rest, but my brain melted after realizing that the myplugin
method posted also contains another crucial error and deviates from the commentary. Not trying to analyze any more of that. Would not recommend using.
精彩评论