If I am applying a function to a javascript array i.e.
var a = [1,2,3,4];
var x;
a.forEach(function(val) {
x = val + 1;
// do some stuff with x
});
Is it better to leave the variable declaration in the outer scope or to put the declaration inside the function? i.e.
var a = [1,2,3,4];
a.forEach(function(val) {
var x = val + 1;
// do some stuff with x
});
What I do not know is if the memory allocation for x is more expensive than the variable lookup process.
If you do not need the variable outside the forEach callback, put it inside. It is simply cleaner that way. Memory is not an issue.
Its better to put it into the loop. There is no performance difference. However using the scope the right way is a good starting point to detect errors:
var something = 5;
a.forEach(el => something = el);
console.log(something); // what is something? Why is it set?
What I do not know is if the memory allocation for x is more expensive than the variable lookup process
It depends. It depends on the exact code, the size of the array, how frequently the code is run, how many scopes there are between the code accessing the variable and the scope where the variable is declared, what optimizations the JavaScript engine on which the code is running does, etc.
So: Write the clearest, simplest code you can, and if you run into a performance problem related to that code, profile changes to see how to address it. Anything else is premature optimization and a waste of your time.
However: With the example given, if you declare it within the callback, x will be a local stack variable, and those are extremely cheap to allocate (in terms of execution time). I can't see that it would really matter either way (if you declare it outside, it's just one scope away), but it happens that in this case, the simplest, cleanest code (declaring it within the callback) is at least likely not to be worse than the alternative, and I'd say almost certainly better. But again: If it's an issue, profile the real code.
Practically, this change control two parameters: Scope and initiation.
Scope: if you need to use this var outside the loop, so you need to declare it out side, else you can drop it in and each iteration and the scope will declare, its probably saves memory outside the scope.
Initiation: in big programs the initiation can be critic time,
each time who the loop takes place you need to declare the var and its wasting time...
Related
I've wanted to switch to Coffeescript for a while now and yesterday I thought I'm finally sold but then I stumbled across Armin Ronachers article on shadowing in Coffeescript.
Coffeescript indeed now abandoned shadowing, an example of that problem would be if you use the same iterator for nested loops.
var arr, hab, i;
arr = [[1, 2], [1, 2, 3], [1, 2, 3]];
for(var i = 0; i < arr.length; i++){
var subArr = arr[i];
(function(){
for(var i = 0; i < subArr.length; i++){
console.log(subArr[i]);
}
})();
}
Because cs only declares variables once I wouldn't be able to do this within coffeescript
Shadowing has been intentionally removed and I'd like to understand why the cs-authors would want to get rid of such a feature?
Update: Here is a better example of why Shadowing is important, derived from an issue regarding this problem on github
PS: I'm not looking for an answer that tells me that I can just insert plain Javascript with backticks.
If you read the discussion on this ticket, you can see Jeremy Ashkenas, the creator of CoffeeScript, explaining some of the reasoning between forbidding explicit shadowing:
We all know that dynamic scope is bad, compared to lexical scope, because it makes it difficult to reason about the value of your variables. With dynamic scope, you can't determine the value of a variable by reading the surrounding source code, because the value depends entirely on the environment at the time the function is called. If variable shadowing is allowed and encouraged, you can't determine the value of a variable without tracking backwards in the source to the closest var variable, because the exact same identifier for a local variable can have completely different values in adjacent scopes. In all cases, when you want to shadow a variable, you can accomplish the same thing by simply choosing a more appropriate name. It's much easier to reason about your code if a local variable name has a single value within the entire lexical scope, and shadowing is forbidden.
So it's a very deliberate choice for CoffeeScript to kill two birds with one stone -- simplifying the language by removing the "var" concept, and forbidding shadowed variables as the natural consequence.
If you search "scope" or "shadowing" in the CoffeeScript issues, you can see that this comes up all the time. I will not opine here, but the gist is that the CoffeeScript Creators believe it leads to simpler code that is less error-prone.
Okay, I will opine for a little bit: shadowing doesn't matter. You can come up with contrived examples that show why either approach is better. The fact is that, with shadowing or not, you need to search "up" the scope chain to understand the life of a variable. If you explicitly declare your variables ala JavaScript, you might be able to short-circuit sooner. But it doesn't matter. If you're ever unsure of what variables are in scope in a given function, you're doing it wrong.
Shadowing is possible in CoffeeScript, without including JavaScript. If you ever actually need a variable that you know is locally scoped, you can get it:
x = 15
do (x = 10) ->
console.log x
console.log x
So on the off-chance that this comes up in practice, there's a fairly simple workaround.
Personally, I prefer the explicitly-declare-every-variable approach, and will offer the following as my "argument":
doSomething = ->
...
someCallback = ->
...
whatever = ->
...
x = 10
...
This works great. Then all of a sudden an intern comes along and adds this line:
x = 20
doSomething = ->
...
someCallback = ->
...
whatever = ->
...
x = 10
...
And bam, the code is broken, but the breakage doesn't show up until way later. Whoops! With var, that wouldn't have happened. But with "usually implicit scoping unless you specify otherwise", it would have. So. Anyway.
I work at a company that uses CoffeeScript on the client and server, and I have never heard of this happening in practice. I think the amount of time saved in not having to type the word var everywhere is greater than the amount of time lost to scoping bugs (that never come up).
Edit:
Since writing this answer, I have seen this bug happen two times in actual code. Each time it's happened, it's been extremely annoying and difficult to debug. My feelings have changed to think that CoffeeScript's choice is bad times all around.
Some CoffeeScript-like JS alternatives, such as LiveScript and coco, use two different assignment operators for this: = to declare variables and := to modify variables in outer scopes. This seems like a more-complicated solution than just preserving the var keyword, and something that also won't hold up well once let is widely usable.
The main issue here isn't shadowing, its CoffeeScript conflating variable initialization and variable reassignment and not allowing the programmer to specify their intent exactly
When the coffee-script compiler sees x = 1, it has no idea whether you meant
I want a new variable, but I forgot I'm already using that name in an upper scope
or
I want to reassign a value to a variable I originally created at the top of my file
This is not how you forbid shadowing in a language. This is how you make a language that punishes users who accidentally reuse a variable name with subtle and hard to detect bugs.
CoffeeScript could've been designed to forbid shadowing but keep declaration and assignment separate by keeping var. The compiler would simply complain about this code:
var x = blah()
var test = ->
var x = 0
with "Variable x already exists (line 4)"
but it would also complain about this code:
x = blah()
test = ->
x = 0;
with "Variable x doesn't exist (line 1)"
However, since var was removed, the compiler has no idea whether you meant meant "declare" or "reassign" and can't help.
Using the same syntax for two different things is not "simpler", even though it may look like it is. I recommend Rich Hickey's talk, Simple made easy where he goes in depth why this is so.
Because cs only declares variables once the loop will not work as intended.
What is the intended way for those loops to work? The condition in while i = 0 < arr.length will always be true if the arr is not empty, so it will be an infinite loop. Even if it's only one while loop that won't work as intended (assuming infinite loops are not what you're looking for):
# This is an infinite loop; don't run it.
while i = 0 < arr.length
console.log arr[i]
i++
The correct way of iterating arrays sequentially is using the for ... in construct:
arr = [[1,2], [1,2,3], [1,2,3]]
for hab in arr
# IDK what "hab" means.
for habElement in hab
console.log habElement
I know that this answer sound like going off on a tangent; that the main point is why CS discourages variable shadowing. But if examples are to be used to argument in favour of or against something, the examples ought to be good. This example doesn't help the idea that variable shadowing should be encouraged.
Update (actual answer)
About the variable shadowing issue, one thing that it worth clarifying is that the discussion is about whether variable shadowing should be allowed between different function scopes, not blocks. Within the same function scope, variables will hoist the whole scope, no matter where they are first assigned; this semantic is inherited from JS:
->
console.log a # No ReferenceError is thrown, as "a" exists in this scope.
a = 5
->
if someCondition()
a = something()
console.log a # "a" will refer to the same variable as above, as the if
# statement does not introduce a new scope.
The question that is sometimes asked is why not adding a way to explicitly declare the scope of a variable, like a let keyword (thus shadowing other variables with the same name in enclosing scopes), or make = always introduce a new variable in that scope, and have something like := to assign variables from enclosing scopes without declaring one in the current scope. The motivation for this would be to avoid this kind of errors:
user = ... # The current user of the application; very important!
# ...
# Many lines after that...
# ...
notifyUsers = (users) ->
for user in users # HO NO! The current user gets overridden by this loop that has nothing to do with it!
user.notify something
CoffeeScript's argument for not having a special syntax for shadowing variables is that you simply shouldn't do this kind of thing. Name your variables clearly. Because even if shadowing would be allowed it would be very confusing to have two variables with two different meanings with the same name, one in an inner scope and one in an enclosing scope.
Use adequate variable names according to how much context you have: if you have little context, e.g. a top-level variable, you'll probably need a very specific name to describe it, like currentGameState (especially if it's not a constant and its value will change with time); if you have more context, you can get away with using less descriptive names (because the context is already there), like loop variables: killedEnemies.forEach (e) -> e.die().
If you want to know more about this design decision, you may be interested in reading Jeremy Ashkenas opinions in these HackerNews threads: link, link; or in the many CoffeeScript issues where this topic is discussed: #1121, #2697 and others.
I'm trying to wrap my head around private variables in Javascript, temporary variables, and the GC. However, I can't quite figure out what would happen in the following situation:
MyClass = function() {
this.myProp = new createjs.Shape();
var tempVar = this.myProp.graphics;
tempVar.rect(0, 0, 10, 100);
tempVar = null;
var isDisposed = false;
this.dispose = function() {
if (isDisposed) return;
isDisposed = true;
}
}
var anInstance = new myClass();
My intention was to have isDisposed represent a private status variable, and tempVar be a use-and-throw variable.
Would tempVar get marked for GC? Would isDisposed be marked for GC too? How is the GC to know when I'm trying to declare a temporary variable meant for disposal, and when I'm trying to have a private variable within the object?
I tried to test the following in Chrome, and it seems as if tempVar never gets GC-ed as long as an instance of myClass exists. So I'm not sure what to believe now. I am incredulous that every single local variable that I create for temporary usage will exist in scope for the lifetime of the object.
Javascript does not have strongly typed objects. By setting tempVar to null, you're not declaring that you don't want to use it any more or marking it for collection as in Java or C#, you're merely assigning it a (perfectly valid) value. It's a trap to begin thinking that just because you made tempVar an "instance" of an object, that the variable is in fact an object and can be treated as such for its whole lifetime.
Basically, variables are just variables in Javascript. They can contain anything. It's like VB or VBScript in that regard. Scalars do undergo boxing in many cases (as in 'a|c'.split('|') making the string into a String) but for the most part, forget that. Functions are first-class objects meaning you can assign them to variables, return them from functions, pass them as parameters, and so on.
Now, to actually destroy something in Javascript, you either remove all references to it (as in the case of an object) or, in the case of an object's properties, you can remove them like this:
delete obj.propertyname;
// or //
delete obj[varContainingPropertyName];
To expand on that point, the following two code snippets achieve identical results:
function abc() {window.alert('blah');}
var abc = function() {window.alert('blah');}
Both create a local variable called abc that happens to be a function. The first one can be thought of as a shortcut for the second one.
However, according to this excellent article on deleting that you brought to my attention, you cannot delete local variables (including functions, which are really also local variables). There are exceptions (if the variable was created using eval, or it is in Global scope and you're not using IE <= 8, or you ARE using IE <= 8 and the variable was created in Global scope implicitly as in x = 1 which is technically a huge bug), so read the article for full details on delete, please.
Another key thing that may be of use to you is to know that in Javascript only functions have scope (and the window in browser implementations or whatever the global scope is in other implementations). Non-function objects and code blocks enclosed in { } do not have scope (and I say it this way since the prototype of Function is Object, so functions are objects too, but special ones). This means that, for example, considering the following code:
function doSomething(x) {
if (x > 0) {
var y = 1;
}
return y;
}
This will return 1 when executed with x > 0 because the scope of variable y is the function, not the block. So in fact it's wrong and misleading to put the var declaration in the block since it is in effect (though perhaps not true practice) hoisted to the function scope.
You should read up on closures in javascript (I cannot vouch for the quality of that link). Doing so will probably help. Any time a variable's function scope is maintained anywhere, then all the function's private variables are also. The best you can do is set them to undefined (which is more "nothing" than "null" is in Javascript) which will release any object references they have, but will not truly deallocate the variable to make it available for GC.
As for general GCing gotchas, be aware that if a function has a closure over a DOM element, and a DOM element somewhere also references that function, neither will be GCed until the page is unloaded or you break the circular reference. In some--or all?--versions of IE, such a circular reference will cause a memory leak and it will never be GCed until the browser is closed.
To try to answer your questions more directly:
tempVar will not be marked for GC until the function it is part of has all references released, because it is a local variable, and local variables in Javascript cannot be deleted.
isDisposed has the same qualities as tempVar.
There is no distinction in Javascript for "temporary variables meant for disposal". In newer versions of ECMAScript, there are actual getters and setters available, to define public (or private?) properties of a function.
A browser's console may provide you with misleading results, as discussed in the article on deleting with Firefox.
It's true, as incredible as it may be, that in Javascript, so long as a variable exists within a closure, that variable remains instantiated. This is not normally a problem, and I have not experienced browsers truly running out of memory due to tiny variables lying around un-garbage-collected. Set a variable to undefined when done with it, and be at ease--I sincerely doubt you will ever experience a problem. If you are concerned, then declare a local object var tmpObj = {tempVar: 'something'}; and when done with it you can issue a delete tmpObj.tempVar;. But in my opinion this will needlessly clutter your code.
Basically, my suggestion is to understand that in coming from other programming languages, you have preconceived notions about how a programming language ought to work. Some of those notions may have validity in terms of the ideal programming language. However, it is probably best if you relinquish those notions and just embrace, at least for now, how Javascript actually works. Until you are truly experienced enough to confidently violate the advice of those who have gone before you (such as I) then you're at greater risk of introducing harmful anti-patterns into your Javascript code than you are likely to be correcting any serious deficit in the language. Not having to Dispose() stuff could be really good news--it's this nasty pervasive task that Javascript simply doesn't require from you, so you can spend more time writing functionality and less time managing the lifetime of variables. Win!
I hope you take my words as kindly as they are meant. I don't by any means consider myself a Javascript expert--just that I have some experience and a solid competence in understanding how to use it and what the pitfalls are.
Thanks for listening!
Could someone please compare and contrast between the costs of creating objects in JavaScript/JQuery and a simple variable declaration?
For Example:
var G = {}
G.obj = (function(){
var x = 10; //'private' attribute, can be accessed internally only
G.y = 20; //'public' property
});
x obviously has a local scope where as Y would be accessible publicly through G with a selector. Are there any significant overheads involved in the latter approach?
Thanks.
Edit: I realize this might sound like a silly question but I am planning an architecture for an HTML5 game, I have to keep little things like these in mind as I move forward.
First, you are not really executing the function in your code block.
G.obj = (function(){
var x = 10; //'private' attribute, can be accessed internally only
G.y = 20; //'public' property
})();
Now, As far as cost of creating local variables v/s global properties is concerned, AFAIK, accessing(getting/setting) a global property would be slightly more expensive as you are traversing up the scope chain. The higher the property in scope chain, the more the cost. However, this is less of an issue IMHO.
The bigger issue is your choice of sticking things in a global store. Using local variables is helpful as local variables dont stick around after the function finishes execution. Therefore, you dont keep unnecessary state in memory. This IMO should drive your design on where to keep state for your application.
For example, would this:
while (true) {
var random = Math.random();
}
... be less efficient than the following, in most implementations?
var random;
while (true) {
random = Math.random();
}
Thanks for your input.
Edit: In case it wasn't obvious, I'm mostly worried about lots of repeated (de)allocations occurring in this example.
JavaScript does not have block scoping.
In the first example, the var text declaration is hoisted out of the while block. In both cases, the variable is declared only once. In both cases, the variable is assigned a value once per iteration of the while loop.
var
function-scoped
hoist to the top of its function
redeclarations of the same name in the same scope are no-ops
No, variables are initiated upon entry into the scope, so random exists before the var statement is even reached.
JavaScript doesn't have block scope, and random's declaration would be hoisted to the top of its scope anyway (variable object).
This depends on the implementation of the interpreter. Strictly speaking, yes, it may have a slightly higher overhead; but depending on the GC mechanism this should be cleared reasonably quickly too.
Douglas Crockford recommends putting all the var assignments at the top of a function, i.e. outwith any loops.
I've heard that it is a good technique to define your variables at the top of a function, so you don't end up with variable hoisting problems. This:
// Beginning of file
function something(){
var a, b, c = 1, d, e;
// Do something
}
// End of file
is a good example (excluding the bad variable names, of course).
My question is: Is this always the best approach? What if you are working with a lot of variables? Should they really all just be plopped on one line?
I'd highly suggest giving Code Complete 2 by Steve McConnell a read. His argument is that you should neither declare all of your variables in one line, nor should should declare them all at the top of a routine. So, don't do this:
function foo() {
var a,
b,
c,
d;
/**
* 20 lines that use a and b
*/
/**
* 10 lines that use c and d
*/
}
Instead, you should declare your variables close to where they are needed. In the above code, that might look like this:
function foo() {
var a,
b;
/**
* 20 lines that use a and b
*/
var c,
d;
/**
* 10 lines that use c and d
*/
}
The benefits are that you can understand at a quick glance what variables are used by a block of code by just looking at the declarations above it. You don't need to read the code to see what variables are set, just which are declared.
Don't write code for the compiler or for the computer. Write it for developers. Your code should be as easy to read as possible, and require as little effort as possible to understand a particular section of code.
"Should they really all just be plopped on one line?"
I don't think so.
Here is how I would write that (ignoring names):
function something(){
var a,
b,
c = 1,
d,
e;
// Do something
}
This only looks silly in the above because 1) the names suck 2) the variables are not assigned in the "declaration" -- most code can be written with immutable (assigned-once) variables and I find this to simplify code. I use this for multiple reasons including clarity and resistance to formatting changes (that is, I can change the initial values, add/or remove declarations, etc, without mucking about the formatting of the other lines).
"Is defining every variable at the top always the best approach?"
I don't think so.
For instance, here is how I write loops:
for (var i = 0; i < x; i++) {
var elm = elms[i];
...
}
And some people will go "BUT THE VAR IS HOISTED TO THE TOP OF THE FUNCTION!" or "A VARIABLE IS FUNCTION-SCOPED!". Well, indeed. However, that allows me to easily visually see that this is an error, even if the JavaScript engine won't help:
for (var i = 0; i < x; i++) {
var elm = elms[i];
...
}
...
// valid JS but since I consider this construct *invalid*
// I know this is a *bug* in my code
alert(elm);
As far as when I assign to variables caught in closures: it depends. If the variable is used in only a single closure I generally put it right above. This lets me know it should only be used in that closure. If the variable is shared (e.g. self) I put it above all the applicable closures -- generally in the "variable declaration section" of the function. This lets me know it has a "function-wide scope" (read: likely to be used in multiple bindings).
To address the "for-each closure issue" -- just learn the language. Keeping variable "declarations" close to the closure does not affect this in anyway. If the construct is not understood, it really doesn't matter how the code is written.
I use these approaches to/because:
Have consistent easy-to-scan code.
Write code that tells me when it's wrong.
I prefer code that is amendable to altering without changing structure.
Self-documenting code means less comments.
I like to "read vertically"
Happy coding.
In languages with block scope, it is usually recommended that variables be declared at the site of first use.
But because JavaScript does not have block scope, it is wiser to declare all of a function's variables at the top of the function. This way you don't fool yourself or other people about the variable's scope.
EDIT: Many people work with several languages simultaneously. Often JavaScript is the only one among them without the block scope.
This is a style question. Not a functionality question.
The javascript parser will take this code
function() {
dostuff();
var i = 4;
}
and turn it into :
function() {
var i;
dostuff();
i = 4;
}
As for the style question. No thank you I thought we left that behind with ANSI C.
What you want to do is declare functions at the top of their "scope"
If the "scope" of a variable is the entire function then declare them at the top. If the "scope" is a subset of a function then declare them at the start of the subset.
treat "scope" as logical scope rather then function scope.
This should ensure maximum readability.
This is really just a matter of preference. For example, if my method only contains a for loop, then I won't extract the loop variables to the top:
var func = function(arr) {
for (var i = 0, len = arr.length; i < len; i++) {
// array processing here
}
}
Almost all other times though I will place ALL variables at the top for hoisting reasons. If you find that there are too many variables at the top of your function, it could be an indication that your method is doing too much work, and should consider extracting a portion of it into some sort of helper method. This will let you organize your variables based on functionality.
I would venture to say that in older structures (such as the C\C++ days) it was important to initialize your variables and assign them a start value. But with the way things have been going, I'm finding that declaring them "when necessary" is a valid implementation. Unless scope is playing a part (for instance you need variable a not only in that function, but also in other functions, too), I would declare on-the-go.
Maybe it's just way of thinking, but I tend to declare things based on scope (If the variable is needed only within an if condition or a few lines of code, I'll declare it there (rather than at the top of my function/class). If I don't go through that code path, I think of it as saving the memory allocation and it won't be declared for "no reason".)
I could be completely wrong, however. Either way, JavaScript will allow you to declare your variables in any fashion you deem easiest to read.