Do conditional statements introduce block scope for variables in JavaScript? - javascript

I have a minor problem with a JavaScript snippet that I hope you can help me solving it.
var z=0;
function xyz() {
if (!z) {
z+=5;
var h=15; // The problem resides here
}
else {
var f=h+7;
alert(f);
}
z++;
return z;
}
When I registered this function to a click event handler on a button element, I was expecting to see by the second iteration of function execution an alert message displaying
22
What I had was a NaN message indicating that the variable h wasn't defined despite the explicit declaration statement within the if branch but when I omitted the var keyword, suddenly the function behaved :)
It's really puzzling for me as I am pretty sure that JS doesn't natively support block scoping except when using the let keyword introduced by Mozilla browsers. I am also darn sure that declaring variables using the var keyword creates local scope for them and therefore they become exclusively accessible within the function in which they are defined.
So, why on the world I have to declare h as a global variable for the function to work?
Any help would be very appreciated as I am new to Web Design and I am coming from graphic design background.
Note: Actually,this was not the real life problem that I faced during coding. I was trying to create a ticker that updates every 10 seconds automatically using the setInterval() method and then suppressing it when the user browses the headlines manually and when he's done, the script takes over once again.
I thought that a more generic and simple example is more suitable to explain the solution without getting into the details of the methods/properties used.
=======
UPDATE
I think I got it now. Functions don't have memories and thus can't remember values generated from previous calls. What I was doing actually is storing the value generated from the first call in a global variable that can be accessed in future calls. But I'm wondering is there any elegant way to achieve the same result other than using global variables?

No. In fact all your local variables are initialized at the beginning of your function. Your example code will be executed like this:
function xyz() {
var h;
var f;
if (!z) {
z+=5;
h=15;
}
else {
f=h+7;
alert(f);
}
z++;
return z;
}
You get NaN because in f=h+7 h is declared but it's value is undefined.
There is a more elegant way: using objects. There are may ways you can create objects, I use the most compact method here:
function MyObject() {
this.z = 0;
// it's safer to initialize all your variables (even if you dn't use the initial value)
this.h = 0;
this.f = 0;
this.xyz = function () {
if (!this.z) {
this.z += 5;
this.h = 15;
} else {
this.f = this.h + 7;
alert(this.f);
}
this.z++;
return this.z;
}
}
var o = new MyObject();
o.xyz();
o.xyz();
There are many-many docs about OOP in JS if you are interested.

Nope, only functions have a local scope. Do not put anything in global scope unless you absolutely have to.

You can use closures to get the result (I think) you want, e.g.
var xyz = (function() {
var z = 0;
var h;
return function() {
var f;
if (!z) {
z += 5;
h = 15;
} else {
f = h + 7;
alert(f);
}
return ++z;
}
})();
the first time nothing is shown, after that 22 is always shown and z increments 6, 7, 8, and so on.
--
Rob

Related

Mutating variables inside a function - is it abuse?

I want to know what the best practices are before I go to my colleagues for a code review.
I know that the following code works. My question is whether relying on closure this way is generally accepted in JavaScript or if there's something problematic here that I'm missing? Thanks
EDIT: updated the snippet to more clearly show what I'm trying to achieve (cleaner, more readable code)
// All this is happening inside a function. Declared vars are not global.
var x, y, z; // lots of variables to declare (to use in closures)
setupVars(true); // lots of variables to setup
useVars(); // lots of variables to use
function setupVars(condition) {
if(condition){
x = 1;
y = 2;
z = 3;
} else {
x = 4;
y = 5;
z = 6;
}
};
function useVars(){
console.log(x);
console.log(y);
console.log(z);
}
Using variables with same names as the global ones, inside a function, is not a good coding practice. In the above code, you should consider renaming x inside the function.
Otherwise, if the function is as simple as the one shown above, you could just do something like this
function modify(value){
return modified_value;
}

Effective javascript book having trouble understanding item 13(Iffy)

Trying to read this wonderful book of effective javascript(but I am still novice)..
In item 13, it talks about immediately invoked function expression to create local scopes.
I unfortunately however cannot wrap my head around below example
function wrapElements(a) {
var result = [], i, n;
for ( i = 0, n = a.length; i < n; i++ ) {
result[i] = function() { return a[i]; };
}
return result;
}
var wrapped = wrapElements([10,20,30,40,50]);
var f = wrapped[0];
f(); // undefined....
I really try to read that page many times but I still don't understand
Especially below statement from the book.
The bug in the program comes from the fact that the programmer apparently expected the function to store the value of i at the time of the nested function was created. But in fact, it contains a reference to i. Since the value of i changes after each function is created, the inner functions end up seeing the final value of i. This is the key point about the closures.
Closures store their outer variable by reference, not by value.
I honestly think I understand closure storing info by reference and not by value but I honestly cannot relate them to above paragraphs.
Can someone please explain this to me in easier terms or point me to article which does this? I was not able to find any that was easy to understand.
Thank you for your time in advance!!
Let me see if I can help you understand a little. The concept of Immediately-Invoked Function Expressions or (the popular term back when I learned them) Self-Executing Anonymous Functions can be a difficult one to grasp and I recommend that you have a solid knowledge of JavaScript before really digging in, but I may be able to help explain it to you in a way that will help you understand.
So - let's start by examining a normal function declaration that can be done one of two ways:
function someFunction (param1, param2) {
//do stuff
};
OR
var someFunction = function (param1, param2) {
//do stuff
};
And to invoke this function, you would call it like so:
someFunction("param1value", "param2value");
Which is great and works exactly how it's supposed to. But what if you need a function that executes or invokes immediately when it's ran, and don't want to add an object to the global namespace? Here's the real benefit of an IIFE (SEAF). Here is the basic structure of an anonymous function:
(function () {
})();
The first set of parenthesis after (function () { pass parameters into the scope of the function. The second set of parenthesis })(); are used to invoke the function and pass parameters into the function. Wrapping the function declaration in parenthesis makes the function anonymous and allows it to execute or invoke immediately.
Let's take a very basic beginning framework example and explain in a little more detail:
(function (window, undefined) {
})(window);
I remember when I first saw this, I couldn't figure what was going on here and what the point was... This function accepts two parameters to pass into the scope of the function, a window object and an undefined object. (function (window, undefined) { Then when we call it, we pass in only one window object (the global window scope). })(window); To help you understand, this would be like writing a function and executing it like this:
function doStuff (window, undefined) {
//do stuff here
};
doStuff(window);
So why don't people just write their code this way instead of worrying about these IIFE's? Well, writing your functions this way, could clog up your global scope, meaning that now you have a doStuff() object defined that is available across the scope of your entire project. If you have a really large project or framework, you typically only want to expose one object to the global scope, and keep everything else anonymous so it doesn't overwrite or get overwritten by additional code that may also be included in the application.
This is really the basics, but to help you understand the syntax a little more, let me do a real basic working example for you, just to help you wrap your head around the concept. In this example, as soon as the code runs, we're just going to multiply two numbers, whichever two numbers you pass into the function. Then we're going to output the result to a text box with the id "result". You can play around with it here: http://jsfiddle.net/k7f4n0mk/
(function (number1, number2) {
document.getElementById("result").value = (number1 * number2);
})(5, 10);
If we were to write this without an IIFE, you would first have to define the function, then invoke it and it would look like this:
function multiply(number1, number2) {
document.getElementById("result").value = (number1 * number2);
};
multiply(5, 10);
You can see this example here: http://jsfiddle.net/k7f4n0mk/1/
Both examples produce the exact same result, and I'm assuming that you're fairly comfortable with the second one since it's one of the very basics of the language, so why should you worry about this whole new way to write a function if you're old way works just fine? Well, again, this goes back to keeping the global scope clean, and protecting the local scope.
Everyone is pretty familiar with the jQuery javascript library. The entire context of jQuery is wrapped in an IIFE and only the jQuery and the alias $ object are exposed to the global scope - that's pretty impressive for everything that jQuery does. Well, if jQuery didn't have this IIFE syntax, then every function that they declared would be available to the global scope and could easily be overwritten by an unknowing user. They could overwrite any of the function that jQuery uses and completely break the library - so we want to protect all of the functions that jQuery uses (local scope) and keep the global scope clean by only exposing the necessary objects (jQuery and $).
I know this has been a really long answer, but I hope that I have been able to help you gain a little more understanding on this subject. Let me know if you have any other questions.
-EDIT-
To the point of your question - let me see if I can help explain in greater detail.
Here is the code that you are using:
function wrapElements(a) {
var result = [], i, n;
for (i = 0, n = a.length; i < n; i++) {
result[i] = function () { return a[i]; };
}
return result;
}
var wrapped = wrapElements([10, 20, 30, 40, 50]);
var f = wrapped[0];
f();
Now, when you call var wrapped = wrapElements([10, 20, 30, 40, 50]);
wrapped is now referencing an array of functions, because that's what you're returning in your for loop:
wrapped = [function () { return a[i]; },function () { return a[i]; },function () { return a[i]; },function () { return a[i]; },function () { return a[i]; }]
Then, when you call var f = wrapped[0], f becomes a reference to the first function in the array
f = function () { return a[i]; }
So, what you are doing in this code, is adding a new function to the array in your loop. If you try to call the function, a and i will be undefined which is why you are receiving an undefined error.
To achieve the desired results, the code would look like this:
function wrapElements(a) {
var result = [], i, n;
for (i = 0, n = a.length; i < n; i++) {
result[i] = a[i];
}
return result;
}
var wrapped = wrapElements([10, 20, 30, 40, 50]);
var f = wrapped[0];
I hope this helps your understanding a little more. Please let me know if you need any further assistance.
This is a very common bug. Let me simplify it for you.
The following program should alert 1, 2 and 3:
for (var i = 1; i <= 3; i++) {
setTimeout(function () {
alert(i);
}, 10);
}
However, as you can see it alerts 4 3 times instead. What's happening is that by the time the function given to setTimeout is called the value of i has changed. That's the same problem that you are facing.
To solve this problem we make use of immediately invoked function expressions (IIFEs).
for (var i = 1; i <=3; i++) {
(function (new_i) {
setTimeout(function () {
alert(new_i);
}, 10);
}(i));
}
By using an IIFE we're creating a new variable called i whose value is the that of the old i. Now when the old i changes, the new i remains the same. Hence we get the expected result.
A better way to write this would be to use the with statement to create a new i as follows:
for (var i = 1; i <= 3; i++) {
with ({ new_i: i }) {
setTimeout(function () {
alert(new_i);
}, 10);
}
}
Using with is better than the IIFE for 2 reasons:
It's cleaner and easier to read and understand.
It's faster because no function is being invoked. Function invocation is slow.
Hope that helps.

How to use scope in JavaScript for Function constructor?

If I were to make a new function using the Function constructor, how could I give it a non-temporary scope to access besides window (meaning the scope only has to be evaluated once, not every time the function is called)? The purpose is to construct multiple variables that require some pretty costly calculations, and I don't want to reconstruct them every time the function is called, but I also don't want to store them in window. Any ideas?
You could bind your function to the specific context using bind keyword:
var context = {};
var f = new Function("args", "return this").bind(context);
f(); // context
Since bind is defined in ECMA 5th, it may not be present in all browsers, here's a workaround
For the above described purpose, you use static functions. You cannot prevent scope from being evaluated at every call, because this is the way JavaScript works, but you can speed it up by not having window in the scoping chain.
var namespace = {};
namespace.someMethod = function() {
// do something here.
};
Now anywhere in your code, you can call that method by using namespace.someMethod();. Just be careful. The above is a static method. You can call it without instantiating. But you MUST NOT use this.property inside a static function. It is a potentially very dangerous operation, as it may give an extension access to the global object and basically un-restricted permissions.
And the above is a static JavaScript method. It does not have window in the scoping chain.
Here's how to create a constructor using the same pattern. When you want to use a constructor, you always instantiate before using. For that you have the new keyword.
var namespace = {};
namespace.coordinate = function(x, y) {
this.x = x;
this.y = y;
};
namespace.coordinate.prototype.addCoordinates = function() {
return this.x + this.y;
};
Now anywhere in your code you can do:
var coordinateObject = new namespace.coordinate(5,10);
// you have created a new instance.
alert(coordinateObject.addCoordinates());// will alert 15;
// now you can make as many as you want. They will behave as instances.
// This means they do not interfere with each other in any way.
// They just have the same properties and methods, but the instance values
// Can be entirely different.
var secondCoordinateObject = new namespace.coordinate(10, 25);
alert(secondCoordinateObject.addCoordinates());// will output 35.
You have successufully created an instance of your namespace.coordinate class. Using the pattern I gave you, you can replicate almost the entire functionality of Java or C or any other Object Oriented language.
var yourNamespace = {
func1: function() {
},
func2: function() {
}
};
...
yourNamespace.func1();
you can call the function that you want by calling the function from name space like this yourNamespace.func1();
The ever-growing method of creating, storing, hiding, revealing, and grouping variables & functions is through the magic of "closures", Javascript's most powerful and yet unsung feature:
var groupObj = (function (setUp) {
// maintained by reference, hidden
var _priVar = setUp * 2;
// maintained by reference, revealed (through returned object)
var _pubVar = 8;
var _pubFunc = function (x) {
_priVar += x;
_pubVar += x;
}
var lostVar = setUp * 99; // not referenced, hidden, so evaporates!
return {
'pubVar' : _pubVar,
'pubFunc' : _pubFunc
}
}(4)); // runs immediately with 4 as setUp, revealing pubVar & pubFunc
Then...
groupObj.pubFunc(7); // runs public function, adds 7 to both variables
alert('public variable: ' + groupObj.pubVar); // alerts public variable
A closure occurs whenever there is a function inside of another function. A variable inside of the outter function will be maintained so long as it is referenced by the inner function, kind of a "no-mans land" where a variable is forced to exist by a reference to it from a lower scope, but is hidden from the higher scope due to the innate principles of Javascript.
There are a few other ways to use closures, replacing the object constructor, one-off conflict-free private functions, and more. There are many posts here about them.

javascript var statement and performance

Option1 : multiple var without assignment
function MyFunction() {
var a = null;
var b = null;
....
var z = null;
a = SomeValue;
b = SomeValue2;
....
}
Option 2: one var statement, no assignment
function MyFunction() {
var a, b ..., z;
a = SomeValue;
b = SomeValue2;
....
}
Option 3: multiple var statements with assignment
function MyFunction() {
var a = SomeValue;
var b = SomeValue2;
....
var z = SomeValue26;
}
Is there any performance benefit of using a particular option? Is it true for both primitive type assignments AND object reference assignments?
Thanks for your input.
"premature optimization is the root of
all evil"
I don't think there will be any significant performance change with any of this options.
(IMO) The third option is the most readable option and closest to dynamic memory allocation like C# etc'. But this is my humble opinion, Choose what you like the most.
If it really bothers you and you can't sleep without an answer, test it with jsPerf.
#Chad made a jsPerf so you can sleep well tonight...
To understand the performance you should first understand hoisting. Let's take the following code:
var x = 1;
function bar(val) {
var returnVal = val * 2;
return returnVal;
}
function foo(val) {
var returnVal = 10;
returnVal *= bar(val);
return returnVal;
}
var y = foo(x);
console.log(y); // 20
Hoisting basically means that the JavaScript interpreter will 'hoist' the variable declaration to the top of its scope. Making this example look more like this:
var x, y;
x = 1;
function bar(val) {
var returnVal;
returnVal = val * 2;
return returnVal;
}
function foo(val) {
var returnVal;
returnVal = 10;
returnVal *= bar(val);
return returnVal;
}
y = foo(x);
console.log(y); // 20
So, in your examples given, Option 2 and 3 will basically do the same thing. Since the interpreter will move those declarations to the top. At that point it's a decision of preference. A lot of people avoid doing something like var x, y, z; saying it's dangerous. I, personally, do it. In whatever scope I'm in I will declare all variables at the top, and then use them below. But either way works.
Now, your first example is the least efficient. After hoisting it will look like this:
function MyFunction() {
var a, b, ... z;
a = null;
b = null;
...
z = null;
a = someValue;
b = someValue2;
...
z = someValueN;
}
It basically results in setting the variables twice.
In Chrome, execution times are identical.
The only real consideration here is optimizing network transfer.
Consider var a=1;var b=2;...;var z=9; versus var a=1,b=2,...,z=9;
If you put a ;varĀ  in front of each identifier, that's 5 bytes (assuming a single-byte character encoding), versus 1 byte for a ,. Thus, declaring 26 variables, you can save 100 bytes by writing varĀ  once and listing identifiers with commas.
Granted it's not a huge savings, but every byte helps when it comes to pushing bits over the network. It's not something to worry a great deal about, but if you find yourself declaring several variables in the same area, using the variable declaration list is an easy way to shave a few bytes off your JS file.
That seems like premature optimization, the root of all evil.
How many times will it be executed? What fraction of of the whole program will this consume?
I will counter your question about performance with a few questions:
Have you noticed an issue with performance?
Have you determined that your var statement was the bottleneck?
Have you tested each version?
I'm going to assume the answer to all of these was no.
None of the options should make any significant difference, although the only way to know for certain is to run them and test. JavaScript being an asynchronous client-side language means that you'd have to run a seriously enormous amount of code to have the var statements be a bottleneck of any sort.
In the end, if you're deciding which version to use, I would recommend using a single var statement without assignment:
function () {
var a,
b,
c,
foo,
bar,
fizz,
buzz;
a = 1;
...
b = 3;
}
The reason for this is that this is essentially how the code will be executed due to variable hoisting. I can then move the initialize statement so where the variable is first used, such as in a for loop:
function foo(arr) {
var i,
l;
...
for (i = 0, l = arr.length; i < l; i++) {
doStuff(arr[i]);
}
...
}
They all basically do the same thing: declare a variable and eventually define it (assign something to it). The only thing you're changing throughout your examples is the order in which that occurs, and even that depends on the browser that is compiling your JavaScript -- some might perform optimizations that others do not.
There are some stylistic guidelines you should follow though, and this answer explains them well. Keep in mind that that answer is technology agnostic and may not apply to JavaScript at all.
Just stay away from option 1 if possible, there is no need to make two assignments.
Even variables declared inside a for loop or other compound statement/block will be available outside its containing block.
You can also do:
function MyFunction() {
var a = SomeValue, b = SomeVavlue2;
}

Interacting with the JavaScript scope chain

Given the following snippet of javascript in a scope:
var x = 10;
function sayx() {
alert(x);
}
sayx();
You would of course expect a message box printing '10', you could do multiple function nesting to interact with how 'x' is determined, because when resolving what x is the environment walks up the scope chain.
You can even do a level of 'recompilation' with eval to inject new scopes at runtime.. for example:
var x = 10;
function sayx() {
alert(x);
}
function wrap(f) {
return eval('(function() { var x = 20;(' + f + ')(); })');
}
wrap(sayx)();
This works because the function will have its toString function called which will return the 'original' source.. thus we essentially create a wrapped version of the function that has a new scope that overrides x.. the result will be an alert box that prints '20' and not '10'.
However, on the surface this could appear to work but the scope chain is broken, the next item in the chain is no longer the same because the function 'f' is now defined at a different location.. even worse is that the scope chain it has inherited could contain many references that the calling function shouldn't have access to.
So, is there a more supported, workable way to inject a scope item? something like:
function withScope(f, scope) { ??? }
---
var x = 10, y = 10;
function dothemath() {
alert(x + y);
}
var haxthemath = withScope(dothemath, { x: 9000 });
haxthemath(); // 9010 not 20
I'm guessing the answer is 'no', some may argue there are 'security' issues with such scope injection, but considering you can do the trick anyway (albeit severely broken) I don't think it is..
The benefits of this would be that you can essentially fake your own pseudo variables.
Thanks in advance.
Edit, just the clarify a little, imagine I wanted to 'withScope' a function that had the following scope chain:
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
I would like to be able to get a function back that effectively had the same chain + a scope I provide.. ie:
withScope(somefunc, { foo: 'bar' })
Would give me
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Ext scope - { foo = 'bar' }
All prior standing variables would be found because my extended scope doesn't say anything about them.
If you are refering by scope to the local variables in the function and/or the closure, I think the answer is no.
You can change the scope of the this keyword by using functionName.call(scope, arg1, ...) or functionName.apply(scope, [arg1, ...]); This could be used together with prototypes to create similar chains as you describe - if something isn't found in the object's own properties, it's looked up in its prototype. If the property is not there, the next prototype in the chain is used and so on.
the answer I think you're looking for is the built in "with" statement.
However, I wouldn't reccomend using it, as it is deprecated, and will very likely not exist in ecmascript 6
The only other way I think you could do this sort of thing is from inside the host application itself, manipulating the javascript environment from the outside. Or, if you're using rhino, you can actually do that from inside javascript, because the link between Java apis and Javascript is just that seamless in rhino. When steve yegge first pointed that out it blew my mind. Manipulate javascript from outside of javascript, but from inside javascript! It's genius!
If you're stuck inside a browser environment, perhaps you can use a javascript interpreter written in javascript, such as narcissus.
Maybe use javascript's built in toString method for functions?
function withScope(f, scope) {
var toExec = "";
for (var prop in scope) {
toExec += "var " + prop + " = scope['" + prop + "'];"
}
toExec += "f = (" + f.toString() + ")";
eval(toExec);
return f;
}
var x = 10;
var f = function() {
console.log(x);
};
withScope(f, {x: 20})();
This seems like a bad idea though...
You if want to play around with scope you might enjoy the let statement provided in Javascript 1.7. Recent versions of Firefox support let.

Categories

Resources