最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - How to extend a jquery plugin's public methods through its prototype? - Stack Overflow

matteradmin6PV0评论

How can I extend a plugin's public methods its prototype?

For instance, I have method1 in my plugin, and I want to add another and more through its .prototype. Is it possible?

var extensionMethods = {
   method2: function(){
        return this;
    }
};

$.fn.MyPlugin.prototype = extensionMethods;

console.log($(".element").MyPlugin());

result,

 Object { Element={...}, Options={...}, method1=function()}

Ideally,

 Object { Element={...}, Options={...}, method1=function(), method2=function(), method2function()}

my plugin boilerplate,

(function ($) {

    // Create the plugin name and defaults once
    var pluginName = 'MyPlugin';

    // Attach the plugin to jQuery namespace.
    $.fn[pluginName] = function(PublicOptions) {

        // Set private defaults.
        var Defaults = {
            param1:       'param1',
            param2:       'param2',
            onSuccess:    function(){}
        };

        // Do a deep copy of the options.
        var Options = $.extend(true, {}, Defaults, PublicOptions);

        // Define a functional object to hold the api.
        var PluginApi = function(Element, Options) {
            this.Element   = Element;
            this.Options   = Options;
        };

        // Define the public api and its public methods.
        PluginApi.prototype = {

            method1: function(PublicOptions) {

                // Process the options.
                var Options = $.extend(true, {}, this.Options, PublicOptions);
                return this.Options;
            }
        };

        //Create a new object of api.
        return new PluginApi(this, Options);
    };

})(jQuery);

Any ideas?

How can I extend a plugin's public methods its prototype?

For instance, I have method1 in my plugin, and I want to add another and more through its .prototype. Is it possible?

var extensionMethods = {
   method2: function(){
        return this;
    }
};

$.fn.MyPlugin.prototype = extensionMethods;

console.log($(".element").MyPlugin());

result,

 Object { Element={...}, Options={...}, method1=function()}

Ideally,

 Object { Element={...}, Options={...}, method1=function(), method2=function(), method2function()}

my plugin boilerplate,

(function ($) {

    // Create the plugin name and defaults once
    var pluginName = 'MyPlugin';

    // Attach the plugin to jQuery namespace.
    $.fn[pluginName] = function(PublicOptions) {

        // Set private defaults.
        var Defaults = {
            param1:       'param1',
            param2:       'param2',
            onSuccess:    function(){}
        };

        // Do a deep copy of the options.
        var Options = $.extend(true, {}, Defaults, PublicOptions);

        // Define a functional object to hold the api.
        var PluginApi = function(Element, Options) {
            this.Element   = Element;
            this.Options   = Options;
        };

        // Define the public api and its public methods.
        PluginApi.prototype = {

            method1: function(PublicOptions) {

                // Process the options.
                var Options = $.extend(true, {}, this.Options, PublicOptions);
                return this.Options;
            }
        };

        //Create a new object of api.
        return new PluginApi(this, Options);
    };

})(jQuery);

Any ideas?

Share Improve this question asked Jan 11, 2015 at 15:32 RunRun 57.4k178 gold badges464 silver badges771 bronze badges 12
  • According to your structure (pretty unfortunate, actually, because this is not jQuery plugin) you can only access PluginApi.prototype via some object returned $(".element").MyPlugin() because PluginApi constructor is local inside IIFE. But this is of course not very good. – dfsq Commented Jan 11, 2015 at 15:39
  • How can I change the structure to allow that then? – Run Commented Jan 11, 2015 at 15:40
  • most jquery plugins return this to maintain jQuery chainability. Why are you so set on wanting to create public methods on prototype? – charlietfl Commented Jan 11, 2015 at 15:40
  • @charlietfl can you please provide an example for chainability? – Run Commented Jan 11, 2015 at 15:46
  • 1 it wraps all the plugin code and insulates it (closure) as well as provides context for $ so plugin won't break on page where other libraries use $ – charlietfl Commented Jan 11, 2015 at 16:28
 |  Show 7 more ments

2 Answers 2

Reset to default 2

I think the best structure you can do in this case would not involve prototypes at all. Check this plugin base:

(function($) {

   // Set private defaults.
    var Defaults = {
        param1: 'param1',
        param2: 'param2',
        onSuccess: function() {}
    };

    // Define the public api and its public methods.
    var PluginApi = {

        extend: function(name, method) {
            PluginApi[name] = method;
            return this;
        },

        init: function(PublicOptions) {

            // Do a deep copy of the options.
            var Options = $.extend(true, {}, Defaults, PublicOptions);

            return this.each(function() {
                console.log('set up plugin logic', this.tagName);
            });
        },

        method1: function() {
            console.log('called: method1');
            return this;
        }
    };

    // Create the plugin name and defaults once
    var pluginName = 'MyPlugin';

    // Attach the plugin to jQuery namespace.
    $.fn[pluginName] = function(method) {

        if (PluginApi[method]) {
            return PluginApi[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } 
        else if (typeof method === 'object' || !method) {
            return PluginApi.init.apply(this, arguments);
        } 
        else {
            $.error('Method ' + method + 'does not exist');
        }
    };

})(jQuery);

This plugin structure allows you to chain methods as expected:

$('h1').MyPlugin('method1').css('color', 'red');

In case of the need to use non-existent method you could do this:

// Extend plugin "prototype" with method2 and use it
$('h1, h2').MyPlugin('extend', 'method2', function(prop, value) {
    return this.css(prop, value);
}).MyPlugin('method2', 'color', 'green');

Check usage example in the demo below.

(function($) {

   // Set private defaults.
    var Defaults = {
        param1: 'param1',
        param2: 'param2',
        onSuccess: function() {}
    };

    // Define the public api and its public methods.
    var PluginApi = {

        extend: function(name, method) {
            PluginApi[name] = method;
            return this;
        },

        init: function(PublicOptions) {
            
            // Do a deep copy of the options.
            var Options = $.extend(true, {}, Defaults, PublicOptions);
            
            return this.each(function() {
                console.log('set up plugin logic', this.tagName);
            });
        },

        method1: function() {
            console.log('called: method1');
            return this;
        }
    };

    // Create the plugin name and defaults once
    var pluginName = 'MyPlugin';

    // Attach the plugin to jQuery namespace.
    $.fn[pluginName] = function(method) {

        if (PluginApi[method]) {
            return PluginApi[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } 
        else if (typeof method === 'object' || !method) {
            return PluginApi.init.apply(this, arguments);
        } 
        else {
            $.error('Method ' + method + 'does not exist');
        }
    };

})(jQuery);


// Call existen method1: should make h1 and h2 red
$('h1, h2').MyPlugin('method1').css('color', 'red');

// Call non-existent method2: should throw error in console
try {
    $('h1, h2').MyPlugin('method2').css('color', 'green');
}
catch (e) {
  // Extend "plugin" prototype with method2
  $('h1, h2').MyPlugin('extend', 'method2', function(prop, value) {
      return this.css(prop, value);
  }).MyPlugin('method2', 'color', 'green');
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>H1</h1>
<h2>H2</h2>

Or it may be more optimal to define a static method extend within $[pluginName] namespace:

// Attach the plugin to jQuery namespace.
$.fn[pluginName] = function(method) {

    if (PluginApi[method]) {
        return PluginApi[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } 
    else if (typeof method === 'object' || !method) {
        return PluginApi.init.apply(this, arguments);
    } 
    else {
        $.error('Method ' + method + 'does not exist');
    }
};

$[pluginName] = {};
$[pluginName].extend = function(name, method) {
    PluginApi[name] = method;
};

and then use it like this when necessary to add additional methods:

$.MyPlugin.extend('method2', function(prop, value) {
    return this.css(prop, value);
});

$('h1, h2').MyPlugin('method2', 'color', 'green');

Final demo: http://plnkr.co/edit/qqlfRqAM84goscU5BFNU?p=preview

You can't extend the prototype outside because you use hidden object PluginApi.

You can try to store PluginApi outside of a plugin function:

$[pluginName] = function(Element, Options) {
    this.Element   = Element;
    this.Options   = Options;
};
$[pluginName].prototype = {
    method1: function(PublicOptions) {
        // Process the options.
        var Options = $.extend(true, {}, this.Options, PublicOptions);
        return this.Options;
    }
};

$.fn[pluginName] = function(PublicOptions) {
    // Set private defaults.
    var Defaults = {
        param1:       'param1',
        param2:       'param2',
        onSuccess:    function(){}
    };

    // Do a deep copy of the options.
    var Options = $.extend(true, {}, Defaults, PublicOptions);

    return new $[pluginName](this, Options);
};

and then you can extend the the prototype:

$.MyPlugin.prototype.method2 = function() {
    return this;
}
Post a comment

comment list (0)

  1. No comments so far