Reputation: 109
I am enumerating through the properties of an object. It works fine when I set the object directly.
I need to use prompt (class assignment) to allow the user to input an object name. The problem is obj returns as a string
How can I cast the value from the prompt to an object?
function enumObject(){
var obj;
var propertyName;
obj = prompt("Please enter an object name","window.navigator");
obj = window.navigator;
if (typeof obj == "object"){
for (propertyName in obj){
document.write(propertyName + " : " + obj[propertyName] + "<br>");
}
}
else {
alert('The object name is undefined.');
}
obj = null;
propertyName = null;
}
enumObject();
Upvotes: 0
Views: 488
Reputation: 147373
I need to use prompt (class assignment) to allow the user to input an object name. The problem is obj returns as a string
How can I cast the value from the prompt to an object?
You can't since Objects don't have names. You can have either variables or object properties whose value is a reference to an object though:
var obj = {};
creates a variable whose name is obj and whose value is a reference to an object.
If you want to dynamically create variables, you can use eval, but it's not recommended. It is very much warned against to use eval to execute random code entered by users since they are completely unaware of the variables that already exist and that you don't want them to mess with.
What you can do is create an object specifically to add properties to, since almost any string value can be used as a property name. So you might do:
function enumObject(){
// markup and div will be used later
var markup = '';
var div;
// Here's where the property names will be stored
var obj = {};
var propertyName = prompt("Please enter an object name", "window.navigator");
obj[propertyName] = {};
// This is redundant since an object was just assigned so it will
// always return true
if (typeof obj[propertyName] == "object") {
// Always perform a hasOwnProperty check so you don't get
// inherited properties, you only want the ones added by the user
// Also, don't re-used variables, create a new one
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// Don't use document.write after the page has finished loading
// as it will clear the entire document first before writing
markup += propertyName + " : " + obj[propertyName] + "<br>";
}
}
// This should never execute since the test should always be true
} else {
alert('The object name is undefined.');
}
// Write to the document without destroying it
div = document.createElement('div');
div.innerHTML = markup;
document.body.appendChild(div);
}
Maybe you want to access object properties based on user defined strings. In that case, you can do something like the following. It only uses eval if the root of the property accessor is not window and only strings that appear to be valid identifiers, not random code:
// Assumes dot notation like window.navigator or foo.bar
function getObjectValueByString(s) {
var identifier, path = [];
// Very simple identifier re
var identifierRe = /^[_$a-z][a-z0-9_$]*$/i;
s = s.split('.');
// Loop over parts of s
for (var i=0, iLen=s.length; i<iLen; i++) {
identifier = s[i];
path.push(identifier);
if (identifierRe.test(identifier)) {
// Get root of accessor
if (i == 0) {
if (identifier == 'window') {
obj = window;
// Only use eval on what appear to be valid identifiers
// not arbitrary code
} else {
obj = eval(identifier);
}
// If not root, get property value
} else {
obj = obj[identifier];
}
// Stop if obj isn't an object
if (typeof obj != 'object') {
// Message if didn't get to end of accessor
if (i < iLen - 1) {
return 'Stopped at ' + path.join('.') + ' = ' + obj;
}
}
} else {
return identifier + ' is not a valid identifier';
}
}
return path.join('.') + ' = ' + obj;
}
To play with it:
<input onblur="console.log(getObjectValueByString(this.value));">
A much more rigorous regular expression for identifier names that excludes reserved words is in the accepted answer for Valid Characters for JavaScript Variable Names.
If only properties of window are required, life becomes much simpler and eval is not needed at all, so nor is the regular expression to check for valid identifiers:
function getWindowValueByString(s) {
var identifier, path = [];
var obj = window;
s = s.split('.');
// Loop over parts of s
for (var i=0, iLen=s.length; i<iLen; i++) {
identifier = s[i];
path.push(identifier);
// Check only using window
if (i == 0) {
if (identifier != 'window') {
return 'Only valid for properties of window';
}
} else {
obj = obj[identifier];
}
// Stop if obj isn't an object
if (typeof obj != 'object') {
// Message if didn't get to end of accessor
if (i < iLen - 1) {
return 'Stopped at ' + path.join('.') + ' = ' + obj;
}
}
}
return path.join('.') + ' = ' + obj;
}
Upvotes: 0
Reputation: 9576
An object name...?!?
Do you want your user to inform a global variable name which refers an object? If so, you could do:
var name = prompt("Enter a global variable name.");
var obj = window[name];
If you want your user to enter a string which will be converted to an object literal, you could do:
var objDef = prompt("Enter a string representing an object");
var obj = eval("(function(){return " + objDef + ";})()");
or...
var objDef = prompt("Enter a string representing an object");
var obj = new Function("return " + objDef)();
If you want to access a object variable in a function scope and you're not using "strict mode", try:
(function(){
var someObj = { b:123, c: 321 };
var name = prompt("Enter an object variable name in local scope.");//Here, your user could enter "someObj"
eval("console.log(" + name + ")");
})();
Upvotes: 1
Reputation: 1015
I would suggest:
function enumObject(){
var obj;
var propertyName;
obj = prompt("Please enter an object name","window.navigator");
window[obj] = {};
if (typeof window[obj] == "object"){
for (propertyName in obj){
document.write(propertyName + " : " + obj[propertyName] + "<br>");
}
}
else {
alert('The object name is undefined.');
}
}
enumObject();
Upvotes: 0