Simon Ilett
Simon Ilett

Reputation: 91

jQuery plugin boiler plate - private method with bound scope?

I've been looking at the plugin boiler plate for jQuery plugins, I find it ok but there is one major flaw in the design or maybe just something I can't figure out.

When I author plugins at the moment, it is easy for me to define publicly exposed methods and private methods that only the plugin has access to.

When I tried to do something similar in the boiler plate I was thwarted.

;(function ( $, window, document, undefined ) {

// Create the defaults once
var 
    pluginName = "defaultPluginName",
    defaults = {
        propertyName: "value"
    };

// The actual plugin constructor
function Plugin ( element, options ) {
        this.element = element;
        this.settings = $.extend( {}, defaults, options );
        this.defaults = defaults;
        this.name = pluginName;
        this.init();
}

Plugin.prototype.init = function() {
    console.log('init')
    console.log(this)
    this.yourOtherFunction();
}
Plugin.prototype.yourOtherFunction = function () {
    console.log('yourOtherFunction')
    console.log(this)
    this.yourOtherFunction2();
}
Plugin.prototype.yourOtherFunction2 = function () {
    privateFunction().bind(this)
}

var privateFunction = function() {
    console.log('private')
    console.log(this)
}   

// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[ pluginName ] = function ( options ) {
    return this.each(function() {
        if ( !$.data( this, "plugin_" + pluginName ) ) {
            $.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
        }
    });
};

})( jQuery, window, document );

$(document).defaultPluginName()

Anyway you can see the function 'privateFunction' it's scope is to the window object, but what I want to be able to do is scope it to the Plugin instance, or basically 'this' from the prototype methods.

What I don't want to do, is pass the scope into each private function as a function argument!

So how can I bind the scope?

Console output

init
Plugin { element=document, settings={...}, defaults={...}, more...}
yourOtherFunction
Plugin { element=document, settings={...}, defaults={...}, more...}
private
Window index.html <-- I want Plugin, not window 

Upvotes: 0

Views: 784

Answers (2)

guari
guari

Reputation: 3820

You are calling privateFunction and then binding this as scope for its result.
So use (as said by @Khanh_TO):

Plugin.prototype.yourOtherFunction2 = function () {
    privateFunction.apply(this,arguments);
}

Instead of:

Plugin.prototype.yourOtherFunction2 = function () {
    privateFunction().bind(this)
}

More details:

bind returns a copy of the function on which is called (the result of privateFunction in your case) after applying the scope you've passed in (this in your case). What bind does is something like:

Function.prototype.bind = function(scope) {
    var _function = this;
    var _args = [];
    for (var i = 0, len = arguments.length-1; i < len; i++){ _args[i] = arguments[i+1]; }
    return function() {
        // returns the same function on which is called (not the same Function object, but
        // another with same properties) with 'this' equal to the first parameter and
        // the remaining specified parameters as parameters of the function returned
        return _function.apply(scope, _args);
        }
}

eg. myFunction.bind(newScope, param1, param2, ...) -> returns an anonymous function which in turns returns the function myFunction(param1, param2,....) with set this = newScope.
So, as a proof of concept, also this code would have worked:

Plugin.prototype.yourOtherFunction2 = function () {
    privateFunction.bind(this)();
}

but you should use the first one since the last one does the same thing with extra passages.

Upvotes: 3

Khanh TO
Khanh TO

Reputation: 48972

Replace:

Plugin.prototype.yourOtherFunction2 = function () {
    privateFunction().bind(this)
}

With

Plugin.prototype.yourOtherFunction2 = function () {
    privateFunction.apply(this,arguments);
}

Upvotes: 2

Related Questions