2

I have a pretty big Javascript script with loads of global variables & functions in it. Then a piece of code that calls one function from this js file: myfunc();

Ok, now I have cloned this script and modified some functionality, all function prototypes and variables are named the same in both scripts. So now I have two scripts loaded and one call to myfunc(), now we have a clash because there are loads of global variables with the same names and two myfunc()s.

What I want to do is wrap this cloned script in a namespace, so that I can modify the original call to: clone.myfunc() which will call the new function, but I also want myfunc() to just refer to the original script. In other words I can't touch the original script (no permissions) and I want to be able to use both the clone and the original at runtime.

This is the script im cloning: http://pastebin.com/6KR5T3Ah

Javascript namespaces seem quite tricky this seems a nice namespace method:

var namespace = {
    foo: function() {
    }

    bar: function() {
    }
}

...

namespace.foo();
}

However that requires using an object, and the script (as posted above) is humongous at nearly 4000 lines, too much to objectize I think?

Anyone know a better solution to avoid namespace pollution, with one script I cant touch and one being a clone of that script. Just so I can call myfunc() and clone.myfunc() and all global variables will behave in their respected scope.

It's either that, or I go through and modify everything to have unique names, which may take a lifetime

This is a Mozilla addon if it helps context wise.

Thanks.

2 Answers 2

6

In general, you can avoid polluting the global namespace really easily. If you have code that looks like this:

var foo;

function bar() {
}

just wrap it in a function and immediately call the function:

(function() {
    var foo;

    function bar() {
    }
})();

Now foo and bar are constrained to that big anonymous function. They can still refer to each other with unqualified names, but they're no longer "global" properties (properties on the window object). This is sometimes called wrapping things up in a closure.

You can "export" things out of that closure in a few ways: 1. Return an object with function properties; 2. If you only need to export one function, just return the function reference; 3. Explicitly assign functions to window properties from within the closure:

// 1. Returning an object with function properties:
var myNamespace = (function() {
    function myfunc() {
        // ...
    }

    return {
        myfunc: myfunc
    };
})();

The call would be to myNameSpace.myfunc().

// 2. Returning just one function
var myFuncReworked = (function() {
    function myfunc() {
        // ...
    }

    return myfunc;
})();

The call would be to myFuncReworked().

// 3. Explicitly assign to `window` property:
(function() {
    function myfunc() {
        // ...
    }

    window.myfunc = myfunc;
})();

The call would be to myfunc() (aka window.myfunc()).

All of this assumes that the script doesn't assume that its various global variables and functions will show up on the window object, of course.

This blog post may be useful in terms of background around the whole "wrapped in a closure" thing, although the thrust of the post is about avoiding anonymous functions (except scoping functions).


Edit Pointy points out (and that makes sense) that this is a plug-in, so if window isn't relevant, that third option can look like this instead:

// 3. Explicitly assign to global property:
(function(global) {           <== Note the new argument
    function myfunc() {
        // ...
    }

    global.myfunc = myfunc;   <== Use the new arg instead of `window`
})(this);                     <== Pass `this` into the function

That works because at global scope, this refers to the global object, which doesn't intrinsically have a "name;" passing it into the function lets us give it one easily. (In web pages, window refers to the global object, but actually window is just a property on the global object that it uses to refer to itself; the technical discussion of that gets...technical fairly quickly, so I'll leave it as I don't think it's hyper-relevant.)

Sign up to request clarification or add additional context in comments.

4 Comments

I think that "window" might not work if it's a Mozilla plugin, but I assume that passing "this" to the wrapper function would work in that context too. I could be wrong of course as I've never done a plugin.
Thanks very much. If I take method 1 above, what happens when the anonymous function is called immediately after its declaration? It's just that I don't want anything (functionality wise) executed until I call myfunc() explicitly somewhere else in the codebase. Also, using method 1, am I correct in thinking I can include as many functions & variables as I want inside that namespace/anonymous function, then just export anything I need to be publicly available?
@Jason: Executing the anonymous function immediately is basically the same as not having the function wrapper there -- the variables get created, the functions get created, but no functions are called unless, well, they're called. :-) And yes, you can include as many functions in there as you like. JavaScript libraries frequently use this idiom so they can have lots of private internal functions and only export the ones the really need.
@Pointy: Good point, I've added a note at the end to generalize
1

It might work to do two things:

  1. Wrap everything in a function and
  2. Explicitly expose your "myfunc"

Add to the top of the file:

(function(global) {

and to the very end:

})(this);

And after you declare/define "myfunc" add:

global['myfunc'] = myfunc;

edit — @TJ explains the workings of this in his answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.