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?
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...
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
Related
Essentially my I am trying to initialize a JavaScript object and have it contain empty objects with a single key. For example:
getOject('one.two.three')
Would result in the object:
{one:{two:{three:''}}}
As far as I can tell, you can't initialize with dynamic key names unless you use array notation
root[dynamicKey] = 'some variable';
so I need to loop through and based on the number of args initialize each one then assign it's value but the syntax doesn't seem to let me do this in any way that I know of.
So, if it were not a loop it would be like this:
jsonifiedForm[rootKey] = {};
jsonifiedForm[rootKey][childKeys[0]] = {};
jsonifiedForm[rootKey][childKeys[0]][childKeys[1]] = $input.val();
I can't think of a way to do this, I am not typically a JS guy so it might be something simple but I couldn't find anything on Google or Stack Overflow
Thank you in advance!
This function should be what you're looking for.
function getOject(str) {
// this turns the string into an array = 'one.two.three' becomes ['one', 'two', 'three']
var arr = str.split('.');
// this will be our final object
var obj = {};
// this is the current level of the object - in the first iteration we will add the "one" object here
var curobj = obj;
var i = 0;
// we loop until the next-to-last element because we want the last element ("three") to contain an empty string instead of an empty object
while (i < (arr.length-1)) {
// add a new level to the object and set the curobj to the new level
curobj[arr[i]] = {};
curobj = curobj[arr[i++]];
}
// finally, we append the empty string to the final object
curobj[arr[i]] = '';
return obj;
}
Because JavaScript references values in variables instead of copying them "into" variables, we can make our initial value, then make a reference to it which we'll move around as we delve down in:
var getOject = function (k, s) {
// initialize our value for return
var o = {},
// get a reference to that object
r = o,
i;
// we'll allow for a string or an array to be passed as keys,
//and an optional sepeartor which we'll default to `.` if not given
if (typeof k === 'string') {
k = k.split(s || '.');
}
// do we have an array now?
if (k && k.length) {
//iterate it
for (i = 0; i < k.length; i += 1) {
// set a property on the referenced object
r[k[i]] = {};
// point the reference to the new level
r = r[k[i]];
}
}
// send back the object
return o;
}
console.log(getOject('one.two.three'));
console.log(getOject('four|five|six', '|'));
r points to the same thing that o does, initially, and as we move the reference (r) deeper into o and write to it, we're building out o as we go.
The two console.log() calls at the end output the following:
Also notice I let you pass in an array to start with if you feel like it, and made the separator a parameter so that you're not stuck with .
How to iterate over an array of literal objects in JavaScript?
I would like to do something like that:
grupo = []; // declare array
text = {}; // declare new object
text.a = "texta"; // declare property "a" of an object.
text.b = "textb";
grupo.push(text); // add object to array
text = {}; // declare new object
text.a = "textc"; // declare property
grupo.push(text); // add object with other property
// Iterate over
for (i=0; i<=grupo.length; i++) {
console.dir(grupo[i].text.a);
}
There are various errors in that code:
You're putting the same object in the array twice, not putting two objects in the array. After you push text into the array, you're just overwriting the a property on the same object and pushing it again. You haven't created a new object.
You haven't declared any of your variables (everywhere you've said "declare" in your comments, those are not declarations), so you're falling prey to The Horror of Implicit Globals. Use var to declare variables.
A line comment should start with //, not \\ (those cause a syntax error)
The for loop at the end should use <, not <=, for its termination condition. For the various ways to loop through arrays in JavaScript, see this question and its answers.
Here's a cleaned-up version of that code:
var text, grupo, i; // Declare variables
text = {}; // Create an object and assign it to the variable
grupo = []; // Create an array and assign it to the variable
text.a = "texta"; // Set the property `a` on the object
text.b = "textb"; // Set the property `b` on the object
grupo.push(text); // Put that object onto the array
text = {}; // Create a second object
text.a = "textc"; // Set the property `a` on that new object
grupo.push(text); // Put that object on the array
for (i=0;i<grupo.length;i++) {
// ^-------------------- Note no =
console.dir(grupo[i].text.a);
}
Do you mean something like this?
for (var key in validation_messages) {
var obj = validation_messages[key];
for (var prop in obj) {
// important check that this is objects own property
// not from prototype prop inherited
if(obj.hasOwnProperty(prop)){
alert(prop + " = " + obj[prop]);
}
}
}
Reference: https://stackoverflow.com/a/921808/1054926
groupo[i] is already a text object so you there is an error there. Also, you don't want to look until your index is <= to the length.
Here is a quick look at what you may be looking for in your loop:
for (i=0;i<grupo.length;i++) {
console.log(i,grupo[i].a);
}
However you will have additional problem when you discover that the value of "a" is not what you may be expecting.
Here another possible "solution"
var text = {};
var grupo = [];
text.a = "texta";
text.b = "textb";
grupo.push(text);
text.a = "textc";
grupo.push(text);
for (var i=0;i < grupo.length;i++) {
var x = grupo[i];
if (x && x.a){
console.log(x.a);
} else {
console.log(x);
}
}
Can someone explain what is happening in the code below? I'd expect toString to get called for either both foo and bar, or neither. How is literal object notation different from adding fields to an object after it is created?
function Obj(v) {
this.v = v;
};
Obj.prototype.toString= function() {
window.alert("to string called for " +
this.v);
return this.v.toString();
}
var foo = new Obj('foo');
var bar = new Obj('bar');
// toString is not called here.
var map = {foo : 'blah'};
// toString is called here.
map[bar] = "blah2";
Why do object literals not use toString() while adding to an existing object does use toString()?
http://jsfiddle.net/pByGJ/2/
The main reason that object literals don't evaluate the identifier to the left of the colon is so you're not force to quote all literal names (as you do in JSON).
Bracket notation forces you to quote property names, if you don't, it will be evaluated as a variable.
The reason toString() does get called in the second example is because bar has to be converted to a string to be used as a property name.
In your first example, you're just creating a literal object (that is the exactly the same as {"foo" : 'blah'}). So that is never using the variable foo
If you want to create an object using a variable name, you can't use literal object notation, you have to use [] which is what forces it to call toString()
Here's a function to create objects with variable names in one expression.
function obj(key, value /*, key, value, ... */) {
var obj = {};
for (var i = 0, ln = arguments.length ; i < ln; i+=2) {
obj[arguments[i]] = arguments[i+1];
}
return obj;
}
Clearer Example
The fact that your variable names and values are the same doesn't help understanding the problem. Let me suggest this code
var foo = new Obj('fooValue');
var bar = new Obj('barValue');
var map = {foo : 'blah'};
map[bar] = "blah2";
// You expect map to be {fooValue: 'blah', barValue: 'blah2'}
// But it's {foo: 'blah', barValue: 'blah2'}
To do what you need, use my obj function
// Almost as clear as literal notation ???
var map = obj(
foo, 'blah',
bar, 'blah2'
);
// map = {fooValue: 'blah', barValue: 'blah2'} Yay!!
keys in an object literal are taken as strings, not interpreted as variables. This:
var map = {foo : 'blah'};
is equivalent to this:
var map = {"foo" : 'blah'};
and this:
var map = {};
map["foo"] = "blah";
but is completely different than this:
var map = {};
map[foo] = "blah";
I have separate javascript files to load custom objects; these objects are designed to extend some default parameters when the main function is read
they each look like
var str1= { path:'url1:, var1:5};
var str2= { path:'url2:, var1:3};
etc...
I have an array of strings(that is generated from loading an rss page) and i want to return the object based on if its name matches the object name. hardcoding it would kind of defeat the purpose
Take a look at this question. It shows how to reference objects by using strings. The only difference I can see is that rather than starting with the window object, you would start at whatever object defines your current scope (e.g. this).
You can use the square bracket notation to refer to object properties whose key name is held in a variable:
var key = 'path';
var str1 = { path: 'url', var1: 1};
var value = str1[key]; // value == 'url';
You can also do:
var str1 = 'a';
var str2 = 'b';
var key = 'str1';
var value = window[key]; // value == 'a';
var map = { "string1": { path: "url1", var1:5},
"string2": { path: "url2", var1:3} };
...
var url = map[yourstring].path;
I have a variable containing a string "Y.Plugin.abcd" and I would like to access an object with the same name...I'm using YUI 3 and attempted the Y.namespace method with no luck.
var nm = "Y.Plugin.abcd";
Y.log(Y.Plugin.abcd); //outputs the correct object
Y.log(Y.namespace(nm)); //outputs an empty object
I'm pretty much looking for any method, YUI or not, to be able to do what is a rather simple task in PHP.
In plain JavaScript, you could probably split your string and then use the subscript notation, as follows:
var nm = "Y.Plugin.abcd";
var nm_array = nm.split('.'); // split the nm string
var obj = window; // set our reference to the global object
for (var i = 0; i < nm_array.length; i++) {
obj = obj[nm_array[i]]; // walk through all the namespaces
}
Y.log(obj); // obj will hold a reference to Y.Plugin.abcd