views:

52

answers:

2

I'm trying to write a function that takes a string representing a namespace (e.g. "MyCompany.UI.LoginPage") and defines each segment of the namespace as an object if it doesn't already exist. For example, if "MyCompany.UI.LoginPage" wasn't an object, it would evaluate this:

MyCompany = {};
MyCompany.UI = {};
MyCompany.UI.LoginPage = {};

I would like to do this by enumerating each character of the "namespace" (string) argument and defining each object as the enumeration reaches period characters.

How can I enumerate the characters of a string in JavaScript?

+2  A: 

Convert the string into an array of characters with this code:

var $letterArray = [];

for (var $i = 1; $i <= $yourString.length; $i++)
{
    $letterArray[$i] = $yourStringtring.substring(($i - 1), $i);
}

Then you can enumerate over each character in the string array $letterArrary

Chris Ballance
Got enough dollar signs there?
icktoofay
I think that using `substring` to get only one character is quite expensive when we have the `charAt` method.
CMS
@CMS Thanks for the recommendation.
Chris Ballance
You're welcome @Chris, JFTR to convert a string to a one-character string array, you can also use the `split` method with an empty string argument, e.g.: `"foo".split("");` will give you an array that looks like: `["f", "o", "o"]`
CMS
I wasn't sure if the .split() method worked with an empty arg. Good to know.
Chris Ballance
@icktoofay It has that many dollar signs because this script is **money**! :-)
Chris Ballance
+2  A: 

You can access the characters of a string directly by its index, using the String.prototype.charAt method:

var str = "foo";
for (var i = 0; i < str.length; i++) {
  alert(str.charAt(i));
}

But I don't think that you want to traverse your namespace string character by character, you can use the String.prototype.split method, to get an array containing the namespace levels using the dot (.) character as a separator, e.g.:

var levels = "MyCompany.UI.LoginPage".split('.');
// levels is an array: ["MyCompany", "UI", "LoginPage"]

But I think your question goes further to this, and I will give you a more advanced starting point, I made a recursive function that will allow you to do exactly what you want, initialize several nested object levels using a string:

Usage:

initializeNS('MyCompany.UI.LoginPage');
// that will create a MyCompany global object

// you can use it on an object to avoid globals also
var topLevel = {};
initializeNS('Foo.Bar.Baz', topLevel);

// or
var One = initializeNS('Two.Three.Four', {});

Implementation:

function initializeNS(ns, obj) {
  var global = (function () { return this;})(), // reference to the global object
      levels = ns.split('.'), first = levels.shift();
  obj = obj || global; //if no object argument supplied declare a global property
  obj[first] = obj[first] || {}; // initialize the "level"
  if (levels.length) { // recursion condition
    initializeNS(levels.join('.'), obj[first]);
  }
  return obj[first]; // return a reference to the top level object
}

You will have to improve this function, for example you will need to sanitize the string...

CMS
I'd suggest changing `obj[first] = {};` to `obj[first] = obj[first] || {};`, so you don't overwrite existing sub-spaces
K Prime
+1 @CMS, I like your method better, much more efficient.
Chris Ballance
@Chris: Thanks!, @K Prime: Yes, great suggestion, I'll apply it in a minute...
CMS