Trying to avoid eval getting array element from window object - javascript

I've got a function that wants to access a global variable, the name of which arrives as a string argument. This is how it looks now, using eval:
function echoVar(whichone){
document.write(eval(whichone));
}
I thought I'd just use the window[] syntax and have this:
function echoVar(whichone) {
document.write(window[whichone]);
}
If I create a var and call it like this, it doc writes ABC as expected:
var abc = "ABC";
echoVar("abc");
If the var I want to access is an array element though, it doesn't work:
var def = ["DEF"];
echoVar("def[0]"); //fails with undefined
Obviously that's actually executing window[def[0]] which rightly gives undefined (because there's no variable called DEF). What I actually want to happen is that it executes window["def"][0].
The only way I know to achieve this, is to do a split on the whichone parameter with "[" as the delimiter and then use the split [0] as the window index and a parseInt on split [1] to get the index, like this:
function echoVar(whichone){
if(whichone.indexOf("[")==-1){
document.write(window[whichone]);
}
else{
var s = whichone.split("[");
var nam = s[0];
var idx = parseInt(s[1]);
document.write( window[nam][idx] );
}
}
Am I overlooking something obvious? I'd rather keep the eval than have to do all that.

If you dislike using eval in your code, you can always do this:
function echoVar(whichone) {
document.write(Function("return " + whichone)());
}

Unless this is some sick experiment, you should never be writing Javascript code that looks like this. This is terrible; you need to re-think your design. I know this isn't what you're looking for, but it's the right answer.

The fact is you've got a piece of a javscript expression in a string so you either have to parse it yourself or use eval to parse it for you unless you change the way it's passed like this:
function echoVar(a,b) {
var x = window[a];
if (b) {
x = x[b];
}
document.write(x);
}
And, then you can pass it differently like this:
var def = ["DEF"];
echoVar("def", 0); // def[0]
You could even make this support multiple dimensions if you needed to.
function echoVar(a) {
var x = window[a];
for (var i = 1; i < arguments.length; i++) {
x = x[arguments[i]];
}
document.write(x);
}
var def = {myObject: {length: 3}}
echoVar("def", "myObject", "length"); // def["myObject"]["length"] or def.myObject.length
You can see it work here: http://jsfiddle.net/jfriend00/dANwq/

It would be simpler to lose the brackets and call the item with dot notation
function reval(s, O){
s= String(s);
O= O || window;
var N= s.split(".");
while(O && N.length) O= O[N.shift()];
return O || s;
}
window.def= ['definition'];
alert(reval('def.0'))
/* returned value: (String)
definition
*/

Related

why doesn't this return an l-value?

Maybe ReSharper or visual studio is wrong, but I don't think that this returns an r-value. I also don't think it actually sets the property in the $parent controller:
function getParentItem(path) {
var obj = $scope.$parent;
var param = null;
var items = path.split(".");
for (var i = 0; i < items.length; i++) {
var item = items[i];
var split = item.split("(");
if (split.length === 2) {
param = split[1].replace(/[\)\']/g, "");
}
obj = obj[split[0]];
}
if (param == null) {
var thisObj = obj;
return thisObj;
} else {
return { obj: obj, param: param };
}
}
If I do this:
getParentItem($scope.someProperty) = "yadda"
I get error marked by probably ReSharper and I think it doesn't actually set the new value
As Amy/Volkan said your code is not valid but I think I get what you want to do. There are lots of ifs but here it goes:
if your $scope.someProperty is string property that you want to reassign on result of the function getParentItem, and your function returns object that can have that param ($scope.someProperty), first you need to figure out which path you pass in but it looks like it's some string separated by dots.
// so then assign result of the function to some variable
// you need to pass somePath to function
let parentItem = getParentItem(somePath);
// then change that property
parentItem[$scope.someProperty] = "yadda";
or another possibility what you might need would be:
parentItem.param[$scope.someProperty] = "yadda";
then do whatever you want with parentItem like put it on $scope or whatever.
If you want better help please do some jsfiddle or something.
The problem is (and I slap my head on how stupid I was) that the leaf branches of this $scope object aren't objects themselves, and in some cases in our code they don't even exist yet. You get so used to $scope being an object you fail to realize that the final elements can't possibly be objects at least in Javascript.
So the solution was to pass the value that I wanted to set as a parameter:
function getParentItem(path, optionalValue)
On the final loop of the parent search, if optionalValue is passed, I can then set the value onto the object:
obj[--last parameter name--] = optionalValue;

Convert string value as variable name in js, like in php [duplicate]

I’ve looked for solutions, but couldn’t find any that work.
I have a variable called onlyVideo.
"onlyVideo" the string gets passed into a function. I want to set the variable onlyVideo inside the function as something. How can I do that?
(There are a number of variables that could be called into the function, so I need it to work dynamically, not hard coded if statements.)
Edit: There’s probably a better way of doing what you’re attempting to do. I asked this early on in my JavaScript adventure. Check out how JavaScript objects work.
A simple intro:
// create JavaScript object
var obj = { "key1": 1 };
// assign - set "key2" to 2
obj.key2 = 2;
// read values
obj.key1 === 1;
obj.key2 === 2;
// read values with a string, same result as above
// but works with special characters and spaces
// and of course variables
obj["key1"] === 1;
obj["key2"] === 2;
// read with a variable
var key1Str = "key1";
obj[key1Str] === 1;
If it's a global variable then window[variableName]
or in your case window["onlyVideo"] should do the trick.
Javascript has an eval() function for such occasions:
function (varString) {
var myVar = eval(varString);
// .....
}
Edit: Sorry, I think I skimmed the question too quickly. This will only get you the variable, to set it you need
function SetTo5(varString) {
var newValue = 5;
eval(varString + " = " + newValue);
}
or if using a string:
function SetToString(varString) {
var newValue = "string";
eval(varString + " = " + "'" + newValue + "'");
}
But I imagine there is a more appropriate way to accomplish what you're looking for? I don't think eval() is something you really want to use unless there's a great reason for it. eval()
As far as eval vs. global variable solutions...
I think there are advantages to each but this is really a false dichotomy.
If you are paranoid of the global namespace just create a temporary namespace & use the same technique.
var tempNamespace = {};
var myString = "myVarProperty";
tempNamespace[myString] = 5;
Pretty sure you could then access as tempNamespace.myVarProperty (now 5), avoiding using window for storage. (The string could also be put directly into the brackets)
var myString = "echoHello";
window[myString] = function() {
alert("Hello!");
}
echoHello();
Say no to the evil eval. Example here: https://jsfiddle.net/Shaz/WmA8t/
You can do like this
var name = "foo";
var value = "Hello foos";
eval("var "+name+" = '"+value+"';");
alert(foo);
You can access the window object as an associative array and set it that way
window["onlyVideo"] = "TEST";
document.write(onlyVideo);
The window['variableName'] method ONLY works if the variable is defined in the global scope. The correct answer is "Refactor". If you can provide an "Object" context then a possible general solution exists, but there are some variables which no global function could resolve based on the scope of the variable.
(function(){
var findMe = 'no way';
})();
If you're trying to access the property of an object, you have to start with the scope of window and go through each property of the object until you get to the one you want. Assuming that a.b.c has been defined somewhere else in the script, you can use the following:
var values = window;
var str = 'a.b.c'.values.split('.');
for(var i=0; i < str.length; i++)
values = values[str[i]];
This will work for getting the property of any object, no matter how deep it is.
It can be done like this
(function(X, Y) {
// X is the local name of the 'class'
// Doo is default value if param X is empty
var X = (typeof X == 'string') ? X: 'Doo';
var Y = (typeof Y == 'string') ? Y: 'doo';
// this refers to the local X defined above
this[X] = function(doo) {
// object variable
this.doo = doo || 'doo it';
}
// prototypal inheritance for methods
// defined by another
this[X].prototype[Y] = function() {
return this.doo || 'doo';
};
// make X global
window[X] = this[X];
}('Dooa', 'dooa')); // give the names here
// test
doo = new Dooa('abc');
doo2 = new Dooa('def');
console.log(doo.dooa());
console.log(doo2.dooa());
The following code makes it easy to refer to each of your DIVs and other HTML elements in JavaScript. This code should be included just before the tag, so that all of the HTML elements have been seen. It should be followed by your JavaScript code.
// For each element with an id (example: 'MyDIV') in the body, create a variable
// for easy reference. An example is below.
var D=document;
var id={}; // All ID elements
var els=document.body.getElementsByTagName('*');
for (var i = 0; i < els.length; i++)
{
thisid = els[i].id;
if (!thisid)
continue;
val=D.getElementById(thisid);
id[thisid]=val;
}
// Usage:
id.MyDIV.innerHTML="hello";
let me make it more clear
function changeStringToVariable(variable, value){
window[variable]=value
}
changeStringToVariable("name", "john doe");
console.log(name);
//this outputs: john doe
let file="newFile";
changeStringToVariable(file, "text file");
console.log(newFile);
//this outputs: text file

Can I access a variable's name as a string after passing it as an argument to another function?

Perhaps a slightly dim question but I'm trying to design something where I'm using javascript / jquery to change the layout of a website and I'd like to see the values of both a variable name and it's current value in another div.
I was just doing $test.append('example string' + exampleVar) a lot so I thought I would make a function called test().
So far I have:
function test (test) {
$test = $('.test');
$test.append(test+"<br>");
}
and then would pass it a variable name as an argument but I can't find any way of making it display the name as a string. I know about making it as an object to access the key and value but that doesn't really seem to work here?
Bit of a long-winded way to do it, but here's an example using an object:
function tester(options) {
var keys = Object.keys(options);
console.log(keys[0] + ': ' + options[keys[0]]); // test: My value
}
tester({ test: 'My value' });
DEMO
You could use a feature of javascript where obj["prop"] is the same as obj.prop
So instead of passing the variable as a variable and hoping to get its name, you use the name as a string to get the variable's value.
If you aren't using namespaces/variables and want to a global/root variable, pass window, eg:
function test(obj, val) {
console.log(val + ": " + obj[val]);
}
var val1 = 1;
var val2 = 2;
test(window, "val1");
test(window, "val2");
(obviously you don't get the name of 'obj' - but maybe it's a start)
if you only have root/global variables (as in the example provided in the question) then you could remove obj:
function test(val) {
console.log(val + ": " + window[val]);
}
var val1 = 1;
var val2 = 2;
test("val1");
test("val2");
It seems what you want to do something like this:
var argumentName = /([^\s,]+)/g;
// fu is a function
// fu.toString look like: function myFunction (param[, param]*) { code }
function getParamNames(fu) {
var f = fu.toString();
return f.slice(f.indexOf('(')+1,f.indexOf(')')).match(argumentName);
}
Then you might want to create an helper which will take every functions:
// I choosed the console as an output, but you can set anything
function displayParameters(fu) {
var _params = getParamNames(fu);
if(_params!==null) {
for(var i=0;i<_params.length; i++) {
console.log(_params[i]);
}
} else { console.log('no parameters'); }
}
And, you will need to call: displayParameters(test);
In a function you will be using a parameter. So in that case the "variable name" will always be the name of the parameter. In this case getting the string value will always be test. I would assume this is not what you want. You were correct that the best way to do this is to use an object and iterate over the key, values. You would do this like:
var test = {
"test" : "value"
};
function test (test) {
var k, $test = $('.test');
for(k in test){
$test.append(k + "<br>");
}
}
Also, I do not think there is a way to get the variable string name. So the above would be the way to get the name of a variable.

Is it possible to assign a variable with a function? [duplicate]

I’ve looked for solutions, but couldn’t find any that work.
I have a variable called onlyVideo.
"onlyVideo" the string gets passed into a function. I want to set the variable onlyVideo inside the function as something. How can I do that?
(There are a number of variables that could be called into the function, so I need it to work dynamically, not hard coded if statements.)
Edit: There’s probably a better way of doing what you’re attempting to do. I asked this early on in my JavaScript adventure. Check out how JavaScript objects work.
A simple intro:
// create JavaScript object
var obj = { "key1": 1 };
// assign - set "key2" to 2
obj.key2 = 2;
// read values
obj.key1 === 1;
obj.key2 === 2;
// read values with a string, same result as above
// but works with special characters and spaces
// and of course variables
obj["key1"] === 1;
obj["key2"] === 2;
// read with a variable
var key1Str = "key1";
obj[key1Str] === 1;
If it's a global variable then window[variableName]
or in your case window["onlyVideo"] should do the trick.
Javascript has an eval() function for such occasions:
function (varString) {
var myVar = eval(varString);
// .....
}
Edit: Sorry, I think I skimmed the question too quickly. This will only get you the variable, to set it you need
function SetTo5(varString) {
var newValue = 5;
eval(varString + " = " + newValue);
}
or if using a string:
function SetToString(varString) {
var newValue = "string";
eval(varString + " = " + "'" + newValue + "'");
}
But I imagine there is a more appropriate way to accomplish what you're looking for? I don't think eval() is something you really want to use unless there's a great reason for it. eval()
As far as eval vs. global variable solutions...
I think there are advantages to each but this is really a false dichotomy.
If you are paranoid of the global namespace just create a temporary namespace & use the same technique.
var tempNamespace = {};
var myString = "myVarProperty";
tempNamespace[myString] = 5;
Pretty sure you could then access as tempNamespace.myVarProperty (now 5), avoiding using window for storage. (The string could also be put directly into the brackets)
var myString = "echoHello";
window[myString] = function() {
alert("Hello!");
}
echoHello();
Say no to the evil eval. Example here: https://jsfiddle.net/Shaz/WmA8t/
You can do like this
var name = "foo";
var value = "Hello foos";
eval("var "+name+" = '"+value+"';");
alert(foo);
You can access the window object as an associative array and set it that way
window["onlyVideo"] = "TEST";
document.write(onlyVideo);
The window['variableName'] method ONLY works if the variable is defined in the global scope. The correct answer is "Refactor". If you can provide an "Object" context then a possible general solution exists, but there are some variables which no global function could resolve based on the scope of the variable.
(function(){
var findMe = 'no way';
})();
If you're trying to access the property of an object, you have to start with the scope of window and go through each property of the object until you get to the one you want. Assuming that a.b.c has been defined somewhere else in the script, you can use the following:
var values = window;
var str = 'a.b.c'.values.split('.');
for(var i=0; i < str.length; i++)
values = values[str[i]];
This will work for getting the property of any object, no matter how deep it is.
It can be done like this
(function(X, Y) {
// X is the local name of the 'class'
// Doo is default value if param X is empty
var X = (typeof X == 'string') ? X: 'Doo';
var Y = (typeof Y == 'string') ? Y: 'doo';
// this refers to the local X defined above
this[X] = function(doo) {
// object variable
this.doo = doo || 'doo it';
}
// prototypal inheritance for methods
// defined by another
this[X].prototype[Y] = function() {
return this.doo || 'doo';
};
// make X global
window[X] = this[X];
}('Dooa', 'dooa')); // give the names here
// test
doo = new Dooa('abc');
doo2 = new Dooa('def');
console.log(doo.dooa());
console.log(doo2.dooa());
The following code makes it easy to refer to each of your DIVs and other HTML elements in JavaScript. This code should be included just before the tag, so that all of the HTML elements have been seen. It should be followed by your JavaScript code.
// For each element with an id (example: 'MyDIV') in the body, create a variable
// for easy reference. An example is below.
var D=document;
var id={}; // All ID elements
var els=document.body.getElementsByTagName('*');
for (var i = 0; i < els.length; i++)
{
thisid = els[i].id;
if (!thisid)
continue;
val=D.getElementById(thisid);
id[thisid]=val;
}
// Usage:
id.MyDIV.innerHTML="hello";
let me make it more clear
function changeStringToVariable(variable, value){
window[variable]=value
}
changeStringToVariable("name", "john doe");
console.log(name);
//this outputs: john doe
let file="newFile";
changeStringToVariable(file, "text file");
console.log(newFile);
//this outputs: text file

Best/efficent way to remember last function result

I got used to using bind to remember the last result of function and to keep track to be able to use the last result for the next result. For instance to concat or join last string to a new string without using outer variables:
function remStr(outStr){
return function c(lastStr,newStr){
if(!newStr)return lastStr;
var all = lastStr+newStr;
return c.bind(null,all);
}.bind(null,outStr);
}
var str = remStr('stack');
str = str('over');
str = str('flow');
str(); // stackoverflow
The problem is that I want to call remStr several times and so bind came into play. But can it be done better or just differently, maybe it turns out that for one case an approach fulfills a task better than remStr?
If I understand your intention correctly, how about just using the closure?
function remStr(outStr) {
return function c(newStr) {
if (!newStr) return outStr;
outStr += newStr;
return c;
}
}
var str = remStr('stack');
str = str('over');
str = str('flow');
str(); // stackoverflow
As mentioned by Tomalak in the comments, JavaScript strings are immutable, so if you intend to use large or many strings, you will probably want to buffer them in an array.
function remStr(outStr) {
var buffer = [outStr || ''];
return function c(newStr) {
if (!newStr) return buffer.join('');
buffer.push(newStr);
return c;
}
}
var str = remStr('stack');
str = str('over');
str = str('flow');
str(); // stackoverflow
You shouldn't be using Function.bind here at all. You can cache the arguments. And then join it.
This approach is widely known as functions are also objects and can have properties. Function.bind is used to change the context of the given function and that isn't what we want.
function concat(word){
return function fn(anWord){
if(!anWord) return fn.words.join("");
(fn.words || (fn.words = [word])).push(anWord);
}
}
Now you can use it like below:
var str = concat("stack");
str("over");
str("flow");
console.log(str()); // "stackoverflow"

Categories

Resources