How to do this without eval() - javascript

for (var i in variables) {
eval('var ' + i + ' = variables[i]');
}
Basically, I want to transfer variables properties to local variables.
Is there an alternative to using eval()
Or which of these is better:
1.
var _ = variables;
for (var i = 0; i < 100000; i++) {
_.test1();
_.test2();
_.test3();
}
2.
with (variables) {
for (var i = 0; i < 100000; i++) {
test1();
test2();
test3();
}
}
3.
var test1 = variables.test1,
test2 = variables.test2,
test3 = variables.test3;
for (var i = 0; i < 100000; i++) {
test1();
test2();
test3();
}
4.
for (var i in variables) eval('var ' + i + ' = variables[i]');
for (var i = 0; i < 100000; i++) {
test1();
test2();
test3();
}

By looking at your comment seems that your major concern is having to reference several times a deeply nested object, avoiding eval and with I would simply recommend you to use an alias identifier, for example:
// some local scope...
var foo = namespace.constructors.blah.dramatic.variables;
// replace foo with something meaningful :)
foo.method1();
foo.method2();
foo.property1;
// etc...
In that way the deeply nested object will already be resolved and referencing your alias will be faster, eval and with IMO would only cause you more problems than benefits in this case.

One alternative is to make the object the current scope. It won't make the properties local variables, but you can access them using the this keyword:
var variables = { a:42, b:1337 };
(function(){
alert(this.a);
alert(this.b);
}).apply(variables);
This has the advantage that you are not copying anything anywhere, you are accessing the properties directly.

Well, I'll post the answer myself.
No.
There is no way to set local variables without knowing the name of the variable without using eval()...
...But using local variables (option 3) is the best way.

Related

Is it bad to duplicate declaring JavaScript variables?

Is it bad to duplicate declaring JavaScript variables? For instance, given the below code, is one approach better than the other? If so, please explain why. Thank you
function func1() {
for (var i = 0; i < 100; i++) {
var myVar=123;
}
}
OR
function func2() {
var myVar;
for (var i = 0; i < 100; i++) {
myVar=123;
}
}
Actually, these code samples are equivalent and will probably compile to the same bytecode.
function func1() {
for (var i = 0; i < 100; i++) {
var myVar=123;
}
}
AND
function func2() {
var myVar;
for (var i = 0; i < 100; i++) {
myVar=123;
}
}
This is because of hoisting, and in fact you could also do:
function func3() {
var i, myVar;
for (i = 0; i < 100; i++) {
myVar=123;
}
}
Although you might save time with function func4() { var myVar=123; } ;)
These are functionally identical.
Javascript takes two passes through code. During the first pass variables are set up (amongst other things).
In your first version, during the first pass of the interpreter it will see that you declare a variable myVar and it will hoist the definition of the variable to the top of the scope (which is the function in this case because loops don't have their own scope in javascript).
Thus in javascript's second pass, when the code is executed (interpreted), everything will be identical.
So, in javascript all variables act as if they were declared at the top of the scope, regardless of where, or if, you declare them.
One of the potentially confusing things about javascript is that it has c like syntax and yet has some significant differences from other c-like languages. And this is one of those differences.
It's generally considered better to declare variables at the beginning of a piece of code (or function), than at random places. One exception being the for-loop.
function func2() {
var myVar; // try to declare all variables here
for (var i = 0; i < 100; i++) { // except for the for-loop variable
myVar = 123;
}
}
Why I'd do this: because other languages work this way as well, so it makes it easier to read. For JavaScript specificity it doesn't really matter since scope works weird in JavaScript.
Main argument for this way of writing the function: readability.

JavaScript: How to determine a variable's scope?

If I do:
var i = j = 0;
Is j a local variable?
Prove it.
After hoisting, your code looks like:
var i;
j = 0;
i = j;
Therefore i is a local variable, but j is not.
j would be a global variable, or get assigned to a variable in an out scope:
(function() { var i = j = 0; })()
// i is undefined
// j is 0
var i = 42;
var j = 1;
(function() { var i = j = 0; })()
// i remains 42
// j is 0
For fun, here is another "proof":
(function() {"use strict"; var i = j = 0;}());
// throws "ReferenceError: assignment to undeclared variable j"
(Read more about strict mode)
Since the declaration of j isn't in the same declaration expression as i, the variable is either created in the outer scope or, if it exists there it will overwrite the value in the outer scope.
The reason why i is now global is because of variable hoisting. You can break this down like this:
1) var i
2) j, which now declares j in the current scope, which is the containing scope since the expression is not bound to the current context because it's not using var.
3) = 0, which now assigns j to 0, and subsequently assigns j to i.
Proof?
(function(){
var i = j = 0;
})();
try{
alert(i);
}catch(e){
alert(e);
}
alert(j);
http://jsfiddle.net/kDGM3/1/
Not particularly proof...nor would I use an exception in a normal program flow unless it was indeed an exceptional case. But it does demonstrate the behavior.
function test(a){
var i=j=0;
return i;
};
test(100);
alert(j);
alert(i);
check if it's on the window object alert(window.j) if it alerts it's value then it's global if not it's local (if it's not in a function when using the var keyword then it's global and without var then it's global no matter were you define it. so j and i are both global). example:
var i = j = 0;
function x(){
var r = 100;
alert(r);
}
alert(window.i); //will alert 0.
alert(window.j); //will alert 0.
x(); // will alert 100.
alert(window.r); //will alert undefined.
or you can use hasOwnProperty like so alert(window.hasOwnProperty("i")) which returns a boolean value.
by the way, trying to test this using jsfiddle will make i return undefined (might have something to do with the way jsfiddle protects it's own global namespace) so you'll need a blank html page to test this

Access a copied integer variable in javascript anonymous method

I am a C# developer and used to the way closures work in C#.
Currently I have to work with anonymous javascript functions and experience a problem with the following snippet:
function ClosureTest() {
var funcArray = new Array();
var i = 0;
while (i < 2) {
var contextCopy = i;
funcArray[i] = function() { alert(contextCopy); return false; };
i++;
}
funcArray[0]();
funcArray[1]();
}
I expect the first funcArray() call to say 0 and the second to say 1. However, they both say 1. How is that possible?
By writing var contextCopy = i I make sure that I create a copy of the i-variable. Then, in each while-iteration I create a completely new function pointer. Each function refers to its own copy of i, which is contextCopy. However, both created functions for some reason refer to the same contextCopy-variable.
How does this work in javascript?
JavaScript has lexical closures, not block closures. Even though you are assigning i to contextCopy, contextCopy is, itself, a lexical member of ClosureTest (which is different from C#, where the {} give you a new scoped block). Try this:
while (i < 2) {
funcArray[i] = (function(value) {
return function(){ alert(value); return false; }
})(i);
i++;
}
Curly braces ({}) in JavaScript do not capture variables as they do in C#.
Only closures (functions) introduce new scope, and capture variables.
var i = 0;
while (i < 2) {
var contextCopy = i;
...
}
is actually interpreted as:
var i, contextCopy;
i = 0;
while (i < 2) {
contextCopy = i;
...
}
To get a copy of the variable, you'll need to wrap the code with a closure:
var i;
i = 0;
while (i < 2) {
(function (contextCopy) {
...
}(i));
}
You don't create a copy of the i variable. Instead, you make this variable GC-dependant of the closures that use it. It means that when the while loop exits, the i variable continues to live in its last state (1) and both closures reference to it.
Another way to put it: closing over a variable does not copy it into your closure (would make little sense for objects), it just makes your closure reference the variable and ensures this variable is not GCed untill the closure is.

Scope of variable in javascript

I have some javascript code that resembles this:
for (i = 0; i < numTimes; i++) {
DoStuff();
}
function DoStuff() {
for (i = 0; i < 100; i++) {
console.log(i);
}
}
I am finding that the second time the DoStuff() is called, the value of i in the loop starts with 1. I assume this is due to the way the scoping of variables work in JS. Other than changing the variable name in the DoStuff() function, what's the cleanest way of resolving this and can someone explain this behavior?
EDIT: Thanks for the responses. It appears that JS has "lexical scope" instead of "block scope". Is this what I am seeing here? Can someone explain what lexical scope is in newbie terms?
for (var i = 0; i < numTimes; i++) {
DoStuff();
}
function DoStuff() {
for (var i = 0; i < 100; i++) {
console.log(i);
}
}
In javascript, any variable that isn't first declared with the var keyword is global. Adding the var keyword makes it function-local, that is local to the function. Javascript doesn't have block scoping, so if for instance you declared a variable with var inside and if block, it would not be local to the if block, it would be local to the function that contains it.
Use the var keyword. This will limit the scope of i
for (var i = 0; i < 100; i++)
Put a var in front of the variable inside the for loop:
for (var i = 0; i < 3; i++) {
console.log(i);
}
for (var i = 0; i < numTimes; i++) {
DoStuff();
}
function DoStuff() {
for (var i = 0; i < 100; i++) {
console.log(i);
}
}
You should declare iterator variable with "var". If you do not, then you declare global scope variable
your i variable is being implicitly set at a global level, meaning it is accessible (and modifiable!) to any script, anywhere. This is a bad thing, as you have just discovered. The solution is to use the var keyword, which limits the variable to the nearest enclosing function:
for(var i=0; i<100; i++){
To elaborate on a previous answer,
changing i = 0 to var i = 0 will give you the behavior you're looking for.
The reason for this is that if you declare without the var you are declaring it as a global variable, whereas declaring with var makes it local within the scope of the function it is defined in. It should be also be noted that variables declared outside a function, with or without var will be global.
More info here
If you don't declare your variable (i.e. using "var i;" or "var i=0;"), it is created as a global variable, and its scope is the whole program. (THIS IS VERY BAD!).
Note also that JavaScript does not have block scope, and so if you declare your variable in the for loop, it still has scope for the entire function.
Change i = 0; to var i = 0; Example:
for (var i = 0; i < numTimes; i++) {
DoStuff();
}
function DoStuff() {
for (var i = 0; i < 100; i++) {
console.log(i);
}
}

Variable declaration warning in VS2008

The following code in VS2008 gives me a "variable is already defined" warning:
if (someVar) {
var a = 1;
}
else {
var a = 2;
}
The warning is given on the second var a = .... To cure this warning I have done:
var a;
if (someVar) {
a = 1;
}
else {
a = 2;
}
But is this the correct way to do it?
Thanks,
AJ
Yes, that is the correct way to do it. There is no block scope in javascript; there is only function scope and global scope.
you could also give each "block" functional scope using anonymous functions, although it's not very practical in this case:
if (someVar) {
(function () {
var a = 1;
})();
}
else {
(function () {
var a = 2;
})();
}
As a side note, this is also why for (var i = 0; ...) is discouraged in favor of var i; for (i = 0; ...), to avoid 2 consecutive loops in the same function both trying to declare the variable i
It depends on how you're using those variables afterwards.
If they relate to the same object, then it's the correct way.
If they relate to different objects, then I'd rename the variables, as this would prevent maintenance issues in the future.
Either way is perfectly valid and fine (both examples ensure that the variable is declared with the var keyword), but generally it's best practice to declare your vars at the top of the current code block, as in your second example.

Categories

Resources