Langdon
Langdon

Reputation: 20093

jQuery Plugin Scoping Issue

Given the example below (click "content" on the right if you're using the jsfiddle link), why does self fall out of scope when it reaches the clickHelper()?

I can think of two ways to fix it... (1) I can pass it in as an argument, or (2) I can define var self; inside of the plugin (above function clickHelper()).

I don't want to do #1 though, because in my real implementation, I have a bunch of arguments already and a bunch of helper functions... I was hoping to use scope to avoid passing self around everywhere.

And I don't want to use #2 because it seems like if this plugin was used for multiple elements on the page, there could be race conditions... my assumption is that jQuery has 1 instance of the plugin, and therefore var self would only exist once.

I'm basically looking for the best practice of keeping this in scope inside of click event raised for a jQuery plugin.

http://jsfiddle.net/QZc9v/

<div id="a1">
    content
</div>

<script type="text/javascript">=
    function info(n, s) {
        var id = (typeof (s.id) == "undefined") ? '' : ': ' + s.id;
        alert(n + ': ' + s + ': ' + typeof (s) + id);
    }

    (function ($) {    
        $.fn.myPlugin = function () {
        function clickHelper() {
            info('self in the Helper...', self);
            self.innerHTML += '2';
        }
        function clickHandler() {
            var self = this;
            info('self in the Handler', self);
            self.innerHTML += '1';
            clickHelper();
        }
        this.bind('click', clickHandler);
        };
    }(jQuery));

    $(function () {
        $('#a1').myPlugin();
    });
</script>

ETA: #1 is probably the best bet if you don't mind the extra arguments, because #2 does race condition/thread safe issues as demonstrated here (click content 1, ok, and then content 2 really quick). You can get away with #2 by defining your helper methods inside your handler method as demonstrated here, which might work well for your if all your helper methods do is support your handler method. And #3, I suppose, instead of calling JavaScript functions like you normally would clickHelper(), just use a proper closure function(this) { var self = this; clickHelper() };.

Upvotes: 0

Views: 734

Answers (1)

Loktar
Loktar

Reputation: 35319

Guide on closures and scoping

Variables are only available to the functions in which they are created. So by creating self inside of clickHelper you are making it a local variable only to the clickHelpers function.

By moving it into myPlugins scope its now accessible to the nested functions.

Live Demo

 $.fn.myPlugin = function () {
        var self = {}; // self declared here instead can be used within this scope now
        function clickHelper() {
            info('self in the Helper...', self);
            self.innerHTML += '2';
        }
        function clickHandler() {
            self = this;
            info('self in the Handler', self);
            self.innerHTML += '1';
            clickHelper();
        }
        this.bind('click', clickHandler);
    };

Upvotes: 1

Related Questions