2

Say i have this function that dynamically creates my namespace for me when I just pass it a string, (I'm pretty sure basically what YUI JS library does):

MyObj.namespace('fn.method.name');

would result in

MyObj.fn.method.name = {}

being created - all three levels being equivalent to an empty object.

Now, what I want to do, though, is make the last level, in this case name, set to a function, but without having to redeclare the newly created object.
So instead of doing this:

function fnName() { /* some code here */ }
MyObj.namespace('fn.method.name');
MyObj.fn.method.name = new fnName();

i want to call something like:

MyObj.add('fn.method.name', fnName);

And internally, the add method would programmatically instantiate the passed in function:

MyObj.fn.method.name = new fnName()

In the way I have it implemented, I can create the namespace object and set it to an empty object, however, when I try to instantiate a passed in function and associate that namespace with the passed in function, it never gets added to the namespace. Instead, an empty object is always returned. Any ideas?

edit: Here is the namespace method. this is attached to the base object as a JSON object, so please ignore the formatting:

namespace: function (ns) {
    var _ns = ns.split('.'), 
        i = 0, nsLen = _ns.length,
        root = this;
    if (_ns[0] === gNS) {
        _ns.shift();
            nsLen = _ns.length;
        }
        for (i = 0; i < nsLen; i++) { 
            // create a property if it doesn't exist 
            var newNs = _ns[i];
            if (typeof root[newNs] === "undefined") {
                root[newNs] = {};
            }
            root = root[newNs];
        }
        return root;
    }

edit2 - removed the passed in fn argument

hellatan
  • 3,517
  • 2
  • 29
  • 37
  • Where do you got the namespace() function from? – Šime Vidas Jan 11 '11 at 14:49
  • 1
    You are contradicting yourself. First you say you want to set `name` to a function, but then you say you want to set it to the result of `new fnName()`. – Šime Vidas Jan 11 '11 at 14:51
  • 1
    Obviously, "all three levels" cannot be empty objects: the fn object contains the method property, and the method object contains the name property. – Šime Vidas Jan 11 '11 at 14:53
  • An API like that would be a pretty bad idea; how is the framework supposed to know what arguments to pass to the constructor? Why not just instantiate whatever you want, and have the namespace initializer just do a simple assignment? – Pointy Jan 11 '11 at 15:03
  • @Sime - Right about them not all being truly empty objects by the time the script is done. However, when you're initializing the objects, i set them to an empty object. – hellatan Jan 11 '11 at 15:28
  • 1
    It'd probably help for you to post the `namespace` function so that people here could edit it to answer your question. – Brian Donovan Jan 11 '11 at 16:00

3 Answers3

1

Were you looking for something like this:

var root = {};

function create(ns, fn) {
   var nsArray = ns.split(/\./);
   var currentNode = root;

   while(nsArray.length > 1) {
      var newNS = nsArray.shift();

      if(typeof currentNode[newNS] === "undefined") {
         currentNode[newNS] = {};
      }

      currentNode = currentNode[newNS];
   }

   if(fn) {
      currentNode[nsArray.shift()] = fn;
   }

   else {
      currentNode[nsArray.shift()] = {};
   }
}

Then:

create("a.b.c");

console.log(root.a);
console.log(root.a.b);
console.log(root.a.b.c);

Gives:

Object { b={...}}
Object { c={...}}
Object {}

And:

create("d.e.f", function() { console.log("o hai"); });

console.log(root.d);
console.log(root.d.e);
console.log(root.d.e.f);

Gives:

Object { e={...}}
Object {}
function()

Calling the function you defined:

root.d.e.f();

Gives:

o hai
Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
  • thanks, Vivin. had to change my script around to get it to work, but seems to work great! – hellatan Jan 11 '11 at 19:26
  • @dtan No problem, glad to help! I wrote it pretty quickly. But you should be able to make it work similarly if you set `currentNode` to `this`. – Vivin Paliath Jan 11 '11 at 20:44
0

Well you haven't given the namespace function but your add function could look something like this:

MyObj.add = function (namespace, value) {

    var names = namespace.split('.'), current = this, name;

    while (names.length > 1) {

        name = names.shift();
        current[name] = {};
        current = current[name];

    }

    current[names[0]] = value;

};

This code assigns the value given to the last part of the namespace. You could modify it to current[names[0] = new value(); if you want the object constructed by the passed in function (and you are assuming the constructor function takes no arguments).

david4dev
  • 4,854
  • 2
  • 28
  • 35
  • i think this will work, david, but Vivin's does a check for whether or not the object exists already. – hellatan Jan 11 '11 at 19:27
0
function ns() {
    var root = window;

    for (var i = 0; i < arguments.length; i++) {
        var arr = arguments[i].split(/\./);

        for (var j = 0; j < arr.length; j++) {
            var item = arr[j];

            if (typeof item !== 'string') {
                root = item;
            } 
            else {
                if (!root[item]) {
                    root[item] = {};
                }
                root = root[item];
            }
        }
        root = window;
    }
}

then you can create using

ns('fn.method.name');

or

ns('fn.method.name','fn.method.secondName');

and call using

fn.method.name

this function creates your namespace on 'window' so alternatively you can use

window.fn.method.name
Yigit Erol
  • 170
  • 1
  • 6
  • 1
    the only problem with this is that you are explicitly making your new namespace an object literal and are unable to attach anything else (ie. functions) as you can see in the answer i chose above. – hellatan Sep 21 '11 at 15:15