1

I'm creating a JS 'library' file, But I want to encapsulate it in it's entirety within an object, to avoid contaminating namespace of the pages that include the file

The twist to this is within a function inside the library I need to call others functions within library by name, eg using window[]

The code below is just a sample there would actually be several hundred functions that could be called by name. It's this that's caused by trouble as I can't get window[] to reference the function, what's the right way to go about this?

I have tried this, in host page:

<script src= "mylib.js"></script>

var oMyLib = new cMyLib(); //there will only ever be one 'instance' of this

In mylib.js everything is contained in one function:

function cMyLib() {

    this.doStuff = function () {
        someFunc(this);  //call another function in the lib
    }
    //    I tried it with prototypes also
    //    cMyLib.prototype.doStuff = function () {
    //        someFunc();
    //    }


    function someFunc(that) {
      var s='anotherFunc1'
      var f = window[s];   //undefined!
      f();
      s='anotherFunc2'
      f=window[s];
      f();
    }

    function anotherFunc1() {}
    function anotherFunc2() {}
}
5
  • 1
    only global functions appear as properties of window, and you don't want to do that (since that's polluting the name space). Why do you think you need to call window['anotherFunc1'] like that? Commented Mar 1, 2016 at 10:16
  • riiight, that makes complete sense, slaps forehead, i'm now thinking if i don't want to use eval, which i don't think is actually that bad, i could make an array of functions referenced by number. its for a processor emulator so the functions are for instructions which directly equate to numbers anyway.. Commented Mar 1, 2016 at 10:42
  • you can't give a function a numeric-only name, but you could do this.insns = {}; this.insns[0x4c] = function lda(...) Commented Mar 1, 2016 at 10:44
  • hmm, maybe I should port my 6809 emulator... oh, and yeah, an array [] would make more sense than an object {}. Commented Mar 1, 2016 at 10:50
  • thanks Alnitak, insns is an array right i was expecting this.insns = []. I recon you should put this in as an answer so I can accept it! Commented Mar 1, 2016 at 10:53

2 Answers 2

1

The functions that you want to reference by name (or actually by number, according to your comments) should be part of that object, and not accessed via window, e.g.:

function cMyLib() {
    // allow call without new
    if (! (this instanceof cMyLib)) {
        return new cMyLib();
    }

    // enforce singleton
    if (this.constructor.singleton) {
        return this.constructor.singleton;
    } else {
        Object.defineProperty(this.constructor, 'singleton', {
            value: this
        });
    }

    // instruction array (no need to expose via `this`)
    var insn = [];
    insn[0x4c] = function lda_immediate() { ... }

    // instruction execution
    this.step = function() {
        var opcode = memory[pc++];
        if (opcode in insn) {
            // `.call` ensures `this` is set inside the instruction fn.
            insn[opcode].call(this);
        } else {
            hcf();
        }
    }
}

Note the extra stuff at the top - convenience code to ensure that only one cMyLib can exist.

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

Comments

0

As long as a function is in parent scope you can just reference it directly, i.e.

function someFunc(that) {
    anotherFunc1();
};

will simply work.

Another thing is that classical way to do this is to wrap everything in a self-calling anonymous function, i.e.

(function() {
    function anotherFunc1() {};
    function anotherFunc2() {};
    this.cMyLib = function() { ... };
})();

But your approach is fine as well.

If you wish to call your functions by dynamic name, then you can store them in a top level object:

(function() {
    var my_functions = {
        anotherFunc1: function() {},
        anotherFunc2: function() {}
    };
    this.cMyLib = function() {
        var name = 'anotherFunc1';
        my_functions[name]();
    };
})();

It's like creating an isolated "global" scope.

Side note: Do not use eval. It is very unsafe and slow. It will backfire at you at some point.

3 Comments

that's great thanks, the thing is i can't really reference the functions directly as there will be several hundred. its for a processor emulator and there will be a function for each instruction. eval is tempting me
@martinc I don't understand your problem. Even if there are millions of them, so what? As long as function is in parent scope you can reference it. If you want to dynamically reference it (like by dynamically generated name), then put them in an object/dictionary.
thanks this is great info and an alternative way, i had to pick one accepted answer though!

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.