Creating a jQuery plugin: best practices regarding functions' visibility?
I'm creating a jQuery plugin. So far it's working fine, but I'm having doubt about the way I'm doing things:
jQuery.fn.myMethod = function() {
return this.each(function(){
MyScope.doSomething(jQuery(this).attr("id"));
});
};
var MyScope = {
// The functions contained in MyScope are extremely linked to the logic
// of this plugin and it wouldn't make a lot of sense to extract them
doSomething: function(id){
// something
doSomethingElse(23);
// some more code
doSomethingElse(55);
},
doSomethingElse: function(someInt){
// some code
}
};
I use MyScope to store all my "private" functions. I don't want the user to be able to go $("p").doSomething()
, but I do need to use them.
I could mo开发者_如何学运维ve everything in the myMethod
function, but it would create a 100 lines long function and people would hate me for it.
What's the best practices in this situation? Are there any great tutorials out there regarding this?
You can encapsulate your functions to do what you want, like this:
jQuery.fn.myMethod = function() {
return this.each(function(){
doSomething(jQuery(this).attr("id"));
});
function doSomething(id){
//do something
}
function doSomethingElse(){
// some code
}
};
You can view a quick demo here
"I could move everything in the myMethod function, but it would create a 100 lines long function and people would hate me for it." ....why?
The code has to be defined somewhere, if you don't want it to be externally accessible there are a few ways, but I don't see why anyone would dislike you doing exactly this. It's all about scope and where you want things, as long as you're not declaring it multiple times and exposing only what you want, I don't see any problem.
There are several styles to declaring it, some with the same effect, the option I gave is one of many, but placing things inside myMethod
is a perfectly reasonable approach.
To be more complete, here's another alternative:
(function($) {
function doSomething(id){
//do something, e.g: doSomethingElse('bob');
}
function doSomethingElse(str){
//some code
}
$.fn.myMethod = function() {
return this.each(function(){
doSomething(jQuery(this).attr("id"));
});
};
})(jQuery);
Or another:
(function($) {
var me = {
doSomething: function(id){
//do something, e.g: this.doSomethingElse('bob');
},
doSomethingElse: function(str){
//some code
}
};
$.fn.myMethod = function() {
return this.each(function(){
me.doSomething(jQuery(this).attr("id"));
});
};
})(jQuery);
Related articles:
- JavaScript Module Pattern: In-Depth
- JavaScript Closures for Dummies
There's nothing wrong with using a large function just to create a new scope. The following keeps doSomething
and doSomethingElse
private and avoids defining new doSomething
and doSomethingElse
functions for each invocation of myMethod
, which is what would happen if you put doSomething
and doSomethingElse
inside myMethod
's definition.
(function() {
function doSomething(id) {
// Something
}
function doSomethingElse() {
// Something else
}
jQuery.fn.myMethod = function() {
return this.each(function(){
doSomething(this.id);
});
};
})();
I would put everything inside the jQuery.fn.myMethod function, to avoid possible namespace collisions, and make for cleaner code. This pattern also allows you to to make private methods which are not accessible from outside the myMethod function.
jQuery.fn.myMethod = function(options) {
// Set up a "that" object, which can be referenced from anywhere inside this function
var that = {};
// If the plugin needs optional arguments, you can define them this way
if (typeof(options) == 'undefined') options = {};
that.options.option1 = options.option1 || 'default value 1';
that.options.option2 = options.option2 || 'default value 2';
that.init = function() {
// psuedo-constructor method, called from end of function definition
}
that.doSomething = function() {
// something
}
that.doSomethingElse = function() {
// something else
}
// Call init method once all methods are defined
that.init();
// Return the matched elements, to allow method chaining
return jQuery(this);
}
精彩评论