简体   繁体   中英

How do I combine anonymous functions?

From looking on SO and elsewhere it doesn't look like there is a way to extend anonymous functions. ...However, see I Google doing something similar in their google analytics (analytics.js) tracking script and I'm not sure how to replicate the same.

Basically I have a bunch of methods wrapped in an anonymous function. I don't want them leaking into the global namespace.

However... I need to be able to let the user optionally load plugins (that are in separate javascript files) that 'extend' the original script. I do this to keep the original script as small as possible. I can't see a way to break up my script into multiple files and then join then together on the fly based on options the user specifies without exposing all of the methods so that they can communicate. This however will also make them available to other people and hence they may not be using the script as intended.

So in summary, I want to have:

(function() {
// Main.js
....
Based on user input combine with plugin1.js so i can call his methods and he can call mine
})();

(function() {
// Plugin1.js
// More methods
})();

Is there any ways or workaround to accomplish this without exposing all my methods?

Use a combination of revealing module pattern and a single global namespace object. Like this:

//main.js
if (window.MY_APP === undefined) {
    window.MY_APP = {};
}

window.MY_APP.main = (function () {
    //Your code
    var registerPlugin = function() { ... },
        unregisterPlugin = function () { ... };


    return { //Here you expose the functions you want to be public
        registerPlugin: registerPlugin,
        unregisterPlug: unregisterPlugin
    };
}());

//Plugin.js
if (window.MY_APP === undefined) {
    window.MY_APP = {};
}

window.MY_APP.myPlugin = (function() {
    //Plugin code


    return {
       //public methods of plugin 
    };
}());

Probable Solution

Here is a fun solution I just figured out. It is pretty much self explanatory and I commented the code. Hope it serves the purpose.

var p1 = (function (self) {
    // private stuff - 
    var hiddenInfo1 = "PlugIn 1's Secret Info";
    var hiddenMethod1 = function () {
        alert(hiddenInfo1);
    }
    // public stuff
    self.exposedMethod = function () {
        alert("PlugIn 1's Public Info");
    }
    self.getPrivateAccess = function () {
        return {
            seal: function () { delete self.getPrivateAccess },
            // - list of shared private stuffs
            hiddenMethod1: hiddenMethod1,
        }
    }
    return self;
})(p1 || {});

Later you create a Master/Combo

var master = (function (self, p1) {
    // get p1's private stuffs.
    var p1sPrivs = p1.getPrivateAccess();
    // now seal p1 so that no one else can request it.
    p1sPrivs.seal();
    // just to make sure, uncomment this line and get a runtime error. ;)
    // p1.getPrivateAccess();

    // let's define a function for the masses....
    self.shoutAll = function () {
        p1.exposedMethod();
        p1sPrivs.hiddenMethod1();
        alert("Master's Public Method");
    }
    return self;
})(master || {}, p1);

// now use it.
master.shoutAll();

The idea comes from this awesome article located at http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html . Especially into the section called Cross-File Private State .

One severe limitation of splitting a module across multiple files is that each file maintains its own private state, and does not get access to the private state of the other files. This can be fixed. Here is an example of a loosely augmented module that will maintain private state across all augmentations:

var MODULE = (function (my) {
    var _private = my._private = my._private || {},
        _seal = my._seal = my._seal || function () {
            delete my._private;
            delete my._seal;
            delete my._unseal;
        },
        _unseal = my._unseal = my._unseal || function () {
            my._private = _private;
            my._seal = _seal;
            my._unseal = _unseal;
        };

    // permanent access to _private, _seal, and _unseal

    return my;
}(MODULE || {}));

Any file can set properties on their local variable _private, and it will be immediately available to the others. Once this module has loaded completely, the application should call MODULE._seal(), which will prevent external access to the internal _private. If this module were to be augmented again, further in the application's lifetime, one of the internal methods, in any file, can call _unseal() before loading the new file, and call _seal() again after it has been executed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM