Access variable from code run in "eval" in Javascript - javascript

I know using eval is not at all recommended and I have read this link too. Set Variable inside Eval (JavaScript)
However, this is what I want to do. Lets say we have some code in a textbox. So I have to take that text, and then find out all the global variables, functions and objects in that code.
My idea was to wrap the code in a namespace, eval it and then iterate through the properties of the namespace to get the results. However, even though the eval runs successfully, I can't access the variable defined there. Is there a better solution or some other way to get this working.
http://jsfiddle.net/DbrEF/2/ - This is the Fiddle here.
The "var code" could actually be arbitrary code. I know its unsafe to do it but I need it for a different context.
Thanks

In 2015, creating a Function object is your best bet here, rather than using eval:
new Function('arg1', 'arg2', 'return arg1 + arg2')(3,4) // returns 7

You might have better luck using a Javascript parser, like the one used by JSHint/JSLint

here's a demo on safely using eval using "use strict"
window.onload = function(){
'use strict';
//use strict forces to run code in "strict mode"
//use strict prevents eval from
//contaminating the immediate scope
//let's test with "foo"
var foo = 'lol';
//now code has "foo" but using "use strict"
//makes code in eval stay in eval
//note that at the last of the code, foo is "returned"
var code = 'var foo = {name: "Spock",greeting: function() {return "Hello " + foo.name;}}; foo';
//store eval'ed code in evalO
var evalstore = eval(code);
console.log(evalstore); //code in eval stays in here, which is "inner foo"
console.log(foo); //"outer foo" is unharmed and daisy fresh
}​;
so whatever code you have, contain it in a function which will serve as your namespace. then have that function returned to the outside world stored as a variable. this demo shows how it can be constructed, however, works only if code is in object literal notation.
window.onload = function() {
'use strict';
var ns = 'lol';
//code must be an object literal
var code = '{name: "Spock",greeting: function(){return "Hello " + foo.name;}}';
//store in a constructor to be returned
var constructorString = 'var ns = function(){return ' + code + '}; ns';
var evalNs = eval(constructorString); //type function/constructor
var evalObj = new evalNs() //object instance
console.log(evalNs); //constructor
console.log(evalObj); //the namespaced object
console.log(ns); //outer "ns" preserved
};​
​

Probably not what exactly OP was looking for but another option is to use outside variables to store values generated inside eval, as in:
var value;
var code = 'var foo = 42';
code = code.replace('var foo', 'value');
eval(code);
value // returns 42;

Related

Variable undefined when using this.str

I have some simple code here that I'm running in Visual Studio Code with Quokka and NodeJS.
var str = "hello"
function printStr(){
console.log(this.str);
}
printStr();
Output:
undefined​​​​​ at ​​​this.str​​​ ​quokka.js:6:4​
I can run this code in my web browser just fine, and it works just fine, printing out "hello".
"use strict"; is not enabled
Screenshot: https://i.imgur.com/IEQwv5D.png
In a browser this will be interpreted as the window object in this case and the variable str will be defined on the window. There is no window object in Node. It's not clear why you are using this at all here rather than using regular scoping rules. This will work in both the browser and Node:
var str = "hello"
function printStr(){
console.log(str); // will see outside scope
}
printStr();
Better yet, pass the value into the function so it doesn't depend on values defined outside its scope:
var str = "hello"
function printStr(s){
console.log(s);
}
printStr(str);
In Node there is a global object, which has some similarity to the browser's window object so code like this can work in Node, but it would be a fairly non-standard way to do this:
global.str = "hello"
function printStr(){
console.log(this.str)
}
printStr();
Inside a function this normally refers to the window object and the variable str is not defined on window.
You may simple call it like
var str = "hello"
function printStr(){
console.log(str);
}
printStr();
I hope mi answer will be to help. The object 'this' is undefined in node JS for the element window not exist and you aren't working with any object or constructor or class.
For example:
var Animal = function(kind) {
this.name = "NN"
this.kind = kind
};
Animal.prototype.printName = function() {console.log(this.name)};
Animal.prototype.setName = function(name){this.name = name}
var a1 = new Animal("Lion");
var a2 = new Animal("Cat");
a1.setName("Robert");
a2.setName("Alex");
a1.printName();
a2.printName();
Please look at the code when I use the sentence this. if you have a questions, please write me! (Y)

Use of var in the global namespace

I'm reading "you don't know javascript" and I find some trouble with one example in the book "This & Object Prototypes".
When discussing the different rules for this, specifically in the "Implicit binding" paragraph, the author gives this example:
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // function reference/alias!
var a = "oops, global"; // `a` also property on global object
bar(); // "oops, global"
However when trying this on JSFiddle I get an undefined output in console instead of the "oops, global".
Conversely, if I define a without var or using window.a I get the output intended by the author regardless of strict mode.
Why is this happening? Did something in ES6 change the way global variables should be declared?
The default settings for JS Fiddle wrap the JS in a function and assign it as an load event handler.
Your tests are not in the global scope.

fn.call(this) versus fn() when defining a CommonJS module

It's common to see CommonJS modules defined using the following idiom:
(function() {
var logThis = function() { console.log(this); }
module.exports = logThis;
}).call(this);
Underscore.js, for example, does this.
I just spend half an hour discussing with a colleague why they invoke the closure with call(this). This will cause the value of this inside the closure to be inherited from the caller, rather than being set to the global object. However, when I tested this in Node.js, the value of this inside the module was always the global object, even when I loaded and ran it like this:
var bar = {};
bar.foo = function() { var foo = require("./foo"); foo(); }
I was really expecting to see the bar object in the console, but actually I see the global object. It then occurred to me that this might be because modules like Underscore.js are also used in a web context. But in that case it would be loaded with a <script> tag so this will always be equal to the global object anyway.
What gives? I'm sure there is a reason for using this construct but I can't see the practical difference in this particular case whether the module is being used in Node.js or in a webpage.
Update: Just to clarify, I can think of a number of cases where this could make a difference. For example, if I say:
var bar = {}
var foo = require("./foo");
bar.foo = foo;
bar.foo();
(Thanks to #Pointy for correcting my original example.)
I would expect the closure in the module to be evaluated when require() is called, which means that the value of this inside it would be bound to the global object, which would be written to the console even though foo() is then invoked as a member of the "bar" object. However, I am seeing the "bar" object in the console even in this example. I guess that this is not being bound to the closure as I expected?
In a nutshell, I'm looking for one example where a module like Underscore.js will have different behavior due to being wrapped in a closure invoked with fn.call(this) instead of just fn(), either in Node.js or in a web page.
Your call to "foo" inside "bar.foo" is made without any context, so the global context is used. The fact that it's inside a function where this refers to "bar" is not relevant; that's just not how JavaScript works. The only thing that matters is how the function is invoked, not where it's invoked, in other words.
If "bar.foo" looked like this:
bar.foo = function() { require("./foo"); foo.call(this); }
then you'd see "bar" in the console. Or, you could do this:
var bar = {};
require("./foo");
bar.foo = foo;
Then calling bar.foo() would also log the "bar" object. (Does that really work in Node? That is, I thought require() returned an object, and that it didn't just leave things in the global scope. I'm a rank novice at Node however.)
edit — OK thanks for updating. Thus, my example would be corrected as follows. First, I think that your module should look like this:
(function() {
var logThis = function() { console.log(this); }
module.exports.logThis = logThis;
}).call(this);
That is, I think that you want to explort the "logThis" function, so it needs to be bound to the "exports" object as a named property.
Then:
var bar = {};
var foo = require("./foo");
// At this point, foo.logThis is the function
bar.foo = foo.logThis;
// Now the "foo" property of "bar" is a reference to the same function
bar.foo(); // logs the "bar" object
var fee = { fie: foo.logThis };
fee.fie(); // logs the "fee" object

Javascript create variable from its name

In PHP we can do this:
$variable = "name_of_variable";
$this->{$variable} = "somevalue";
how to do this in javascript?
where use case should look like:
function Apple(){
var name = "variable_name";
this.(name) = "value";
}
console.log(new Apple());
to output
[Apple: {variable_name:"value"}]
try:
this[name] = "value";
All objects can use dot and array notation for variable access.
Also note, this will allow you to create name value pairs that are inaccessible via dot notation:
var foo = {};
foo['bar-baz'] = 'fizzbuzz';
alert(foo.bar-baz); //this will not work because `-` is subtraction
alert(foo['bar-baz']); //this will work fine
If you are creating a new object literal, you can use string literals for the names for values with special characters:
var foo = {'bar-baz':'fizzbuzz'};
But you will not be able to use variables as the key within an object literal because they are interpreted as the name to use:
var foo = 'fizz';
var bar = { foo:'buzz' }
alert( bar.fizz ); //this will not work because `foo` was the key provided
alert( bar.foo ); //alerts 'buzz'
Because other answerers are mentioning eval, I will explain a case where eval could be useful.
Warning! Code using eval is evil, proceed with caution.
If you need to use a variable with a dynamic name, and that variable does not exist on another object.
It's important to know that calling var foo in the global context attaches the new variable to the global object (typically window). In a closure, however, the variable created by var foo exists only within the context of the closure, and is not attached to any particular object.
If you need a dynamic variable name within a closure it is better to use a container object:
var container = {};
container[foo] = 'bar';
So with that all being said, if a dynamic variable name is required and a container object is not able to be used, eval can be used to create/access/modify a dynamic variable name.
var evalString = ['var', variableName, '=', String.quote(variableValue), ';'].join(' ')
eval( evalString );
You can use square bracket notation in Javascript:
variable = "name_of_variable";
window[variable] = "somevalue";
You can do this with any object in Javascript.
var name = "var_name";
var obj = {};
obj[name] = 'value';
alert(obj.var_name);
I suggest using associative arrays to do whatever you're trying to do as they are significantly cleaner and easier to debug.
However if you really insist, you can use eval() to accomplish this:
variable = "name_of_variable";
eval(variable + " = \"somevalue\""); // this will work, but please do not do it
alert(name_of_variable);
EDIT: It his just come to my attention that a significantly easier (and better) way of doing this is by simply accessing the window object:
window[variable] = "somevalue";
http://jsfiddle.net/WJCrB/
window['name_of_variable'] = 'somevalue';
or
eval('var ' + variable_name + ' = ' + variable_name + ';');
Beyond that, don't do this. Variable variables are NEVER a good idea and make it nearly impossible to debug problems when (invariably) things break.

Accessing "pseudo-globals" by their name as a string

I am now in the process of removing most globals from my code by enclosing everything in a function, turning the globals into "pseudo globals," that are all accessible from anywhere inside that function block.
(function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
(technically this is only for my "release version", where I append all my files together into a single file and surround them with the above....my dev version still has typically one global per js file)
This all works great except for one thing...there is one important place where I need to access some of these "globals" by string name. Previously, I could have done this:
var name = "g";
alert (window[name]);
and it did the same as
alert(g);
Now -- from inside the block -- I would like to do the same, on my pseudo-globals. But I can't, since they are no longer members of any parent object ("window"), even though are in scope.
Any way to access them by string?
Thanks...
Basically no, as answered indirectly by this question: Javascript equivalent of Python's locals()?
Your only real option would be to use eval, which is usually not a good or even safe idea, as described in this question: Why is using the JavaScript eval function a bad idea?
If the string name of those variables really and truly is defined in a safe way (e.g. not through user-input or anything), then I would recommend just using eval. Just be sure to think really long and hard about this and whether there is not perhaps a better way to do this.
You can name the function you are using to wrap the entire code.
Then set the "global" variable as a member of that function (remember functions are objects in JavaScript).
Then, you can access the variable exactly as you did before....just use the name of the function instead of "window".
It would look something like this:
var myApp = new (function myApp(){
this.g = "world";
//in the same scope
alert ( "Hello " + this["g"]);
})();
//outside
alert ( "Hello " + myApp["g"]);
if you want to access something in a global scope, you have to put something out there. in your case it's probably an object which references your closed off function.
var obj1 = new (function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
you can add a method or property as a getter for g. if the value of g isn't constant you might do like
this.getG = function() { return g; };
you can work from there to access items by name, like
alert( obj1["getG"]() );
alert( window["obj1"]["getG"]() );

Categories

Resources