Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Include JS file within private scope

Tags:

javascript

I simply want the ability to include a JS file, but not have it evaluated in the global scope.

I have skimmed over labjs and requirejs, and although they can do 1000 other things it doesn't seem that either is able to solve this problem.

I am aware that I could wrap the code of foo.js such that it expects a certain context, and can act within in, but that is not what I'm looking for (having to alter the source files). Rather, I would like the source JS files to remain as any other JS file that doesn't need any sort of metadata or any resolving of the runtime execution context via code in the included file itself; outside of the included file, that is ok.

Some simple demonstrations for clarity:

/*
 * Example 1 - apply to current context
 */
function x() {  
    include('foo.js'); // provides foo()
    foo(); // ok!
}
foo(); // not ok!


/*
 * Example 2 - apply to namespace context
 */
include.apply(ns, ['foo.js']); // provides foo()
ns.foo(); // ok!
foo(); // not ok!

I know that this can likely be achieved using eval() or by creating a new Function with the string, but I am hoping that there is a better solution.

like image 449
ken Avatar asked Feb 14 '11 22:02

ken


People also ask

How do I include a JavaScript file in another?

To include an external JavaScript file, we can use the script tag with the attribute src . You've already used the src attribute when using images. The value for the src attribute should be the path to your JavaScript file. This script tag should be included between the <head> tags in your HTML document.

Should I put JavaScript in a separate file?

Placing scripts in external files has some advantages: It separates HTML and code. It makes HTML and JavaScript easier to read and maintain. Cached JavaScript files can speed up page loads.

What is external file in JavaScript?

External JavaScript is when the JavaScript Code(script) is written in another file having an extension . js and then we link this file inside the <head> or<body> tag of our HTML file in which the code is to be added.


2 Answers

I do not think it's possible to do so in ways other than what you outlined yourself.

One solution is to wrap the code in a function on the server side and write an include function that loads the js file and responds with the namespace of the function. I think of a solution similar to the require function in node.js.

Wrapped code on serverside

require.response('foo', function(exports) {

    // Content in foo.js
    exports.a = function() { return 'A'; }
    this.b = function() { return 'B'; }
    function c() { return 'c'); }

});

Client side js:

window['require'] = (function() {

    var list = {};
    function require(name, cb) {
        if (list[name]) {
            if (list[name].ns) {
                cb(list[name].ns);
            }
            else {
                list[name].cb.push(cb);
            }
        }
        else {
            list[name] = {cb: [cb]};

            // Code to load js file

        }
    }

    require.response = function(name, func) {
        var ns = {};
        list[name].ns = ns;
        func.call(ns);
        for(var i = 0, l = list[name].cb; i < l; i++) {
            list[name].cb[i](ns);
        }
    }

    return require;

}());

Example usage:

require('foo', function(foo) {
    foo.a(); // ok
    foo.b(); // ok
    foo.c(); // error
};

foo.a(); // error
this.a(); // error
c(); // error
like image 90
Christian Tellnes Avatar answered Oct 17 '22 00:10

Christian Tellnes


There is no clean way to do this without relying on the included source files to conform to some sort of pattern (I can think of the possibility of injecting each file into its own iframe, so they run with their own window, but I don't think that's ideal).

That doesn't necessarily mean that you cannot achieve decoupling of the included files (without awareness of the runtime context as you say), but the files will still need to be well-behaved.

The CommonJS Module system (which RequireJS supports) shows one way to achieve this. By wrapping code in a function that provides an exports object, and assigning all (previously) global properties to this object, RequireJS can then return this object for you to assign to any object in any scope.

For example:

function x() {  
    var foo = require('foo.js').foo; // provides foo()
    foo(); // ok!
}
foo(); // not ok!

var ns = require('foo.js');
ns.foo(); // ok!
foo(); // not ok!

Yes, this requires editing the source files, but it still provides the benefits you're after.

like image 43
David Tang Avatar answered Oct 16 '22 23:10

David Tang