I'm having difficulty understanding variable shadowing in JavaScript based on scopes. Consider this small code fragment:
var k = {
prop1: 'test',
prop2: 'anotherTest'
}
for(var k = 0; k < 10; k++) {
console.log(k);
}
//prints number
console.log(typeof k);
//prints 10
console.log(k);
//undefined
console.log(k.prop1);
This is fine, because owing to the immediate function scope, the loop counter variable k shadows the json variable k we declated earlier. Hence the json variable k becomes inaccessible so to speak.
Question:
In terms of memory allocation, now that there is no way to access
the original json var k, is it eligible for garbage collection? Will
the allocated memory be freed? Or the 'reference-orphaned' variable
still live on? If yes, why and for how long?
Is there a way of accessing the original json var k WITHOUT writing
any code before the for loop?
Now consider another slightly modified code fragment:
var k = {
prop1: 'test',
prop2: 'anotherTest'
}
var m = {
prop1: k
}
for(var k = 0; k < 11; k++) {
console.log(k);
}
//prints number
console.log(typeof k);
//prints 10
console.log(k);
//undefined
console.log(k.prop1);
//reference altered? No, this reference points to the original json k
//firebug dumps object to console
console.log(m.prop1);
Question:
This time, we hold a reference to the original k before hand, in
another json object. And surely, the memory will not be
de-allocated. But, wouldn't evaluating m.prop1 resolve to an updated
integer k, with a value of 10? Why isn't this resolution leading to
the loop counter with value 10?
1# In terms of memory allocation, now that there is no way to access the original json var k, is it eligible for garbage collection? Will the allocated memory be freed? Or the 'reference-orphaned' variable still live on? If yes, why and for how long?
There is only one variable called k. var does not "declare a variable"1 in the sense of other languages. There is no shadowing here. Rather, it is an annotation lifted to the top of the function.
The object that was previously known by k is no longer strongly reachable and thus can be reclaimed. (Exactly when is implementation dependent, but it is eligible.)
2# Is there a way of accessing the original json var k WITHOUT writing any code before the for loop?
There is only one variable called k. var does not "declare a variable"1 in the sense of other languages. There is no shadowing here. Rather, it is an annotation lifted to the top of the function.
The assignment in the loop overwrites the same k variable.
3# This time, we hold a reference to the original k before hand, in another json object. And surely, the memory will not be de-allocated. But, wouldn't evaluating m.prop1 resolve to an updated integer k, with a value of 10? Why isn't this resolution leading to the loop counter with value 10?
Variables are not objects. Expressions, including variable names, are eagerly evaluated in JavaScript. The object named by the variable k when m = { prop1: k } was evaluated is now named by m.prop1. Assigning a new value to the variable k thus has no effect to what k previously evaluated to.
The only references to variables in JavaScript appear on the left-hand-side of an assignment or to operators like typeof or del. Variables are never references in an expression production otherwise. Do not confuse references with Call-By-Object-Sharing, or "object mutating", semantics: changing a property of an object mutates that object. (As seen, some types like number are immutable and do not allow custom properties to "stick".)
The above assumes the the code appears in a function. The rules for var are slightly different when outside of any function -- in that case it does not declare a local variable, rather k would just (still) refer to the global window.k property.
1 The correct terminology is "declares"; however, I find that thinking of it as an annotation, as it is a function-wide attribute about x and is not "evaluated" in the sense of a statement, is more clear. For example, both of these functions are equivalent:
function () { var x = 1; return x }
function () { x = 1; return x; var x }
See also:
JavaScript Scoping and Hoisting
Difference between using var and not using var in JavaScript (the answer by kangax)
Related
This is not really a question per se, but I am looking for information on why JavaScript creates a new value whenever something is reassigned.
For example, a for loop:
for(let i = 0; i < 1000; i++)
console.log(i);
I have researched that all primitives are immutable and reassigning them actually creates a new value in memory, why not overwrite the existing address?
It seems inefficient that a for loop running will create 100 unused locations when it completes when it could have used 1. It seems strange to me, but I am sure there is a valid reason for it?
Reassigning a primitive value to a variable overwrites the value at the address that the variable points to with a copy of the primitive value.
This loop will overwrite the value at the address that the variable i points to 1000 times. It will not allocate 1000 addresses in memory.
for(let i = 0; i < 1000; i++) {console.log(i);}
What is true is that if you assign to a variable a primitive value from another variable the value will be copied and both variables would point to different locations in memory. You can check it:
let a = 10;
let b = a; // the value 10 from a gets copied to b
a = 20; // the value 10 gets overwritten by 20 in a
console.log(b); // prints 10
Edit:
To answer the question directly: saying that js primitive values are immutable is another way of saying that they get assigned by value as opposed to arrays and objects that get assigned by reference (or are mutable).
Whether a new memory allocation happens or not on each assignment of a primitive value to a variable is an implementation detail, but you can trust that it is done in the most efficient way by modern js engines.
If you search for script solutions online the provided examples often declare all variables as global with var a = 'something'; var b = 123; before the function is staring an algorithm on those variables. Then within the functions sometimes more global variables are declared to hold in between results up to the point the function returns the output of whatever the algorithm is doing.
I wonder now if declaring one single variable once inside the function within an object as an array to hold all in-between results as properties is or isn't more efficient?
For example is example1 or example2 causing more memory usage when the loop would be 100.000 times?
A global function using global variables in a loop
var a = 10, b = 2.33, s = 'example1'
function do1000Times(a,b,s) {
var result = '';
for (var i = 0; i < 1000; i++) {
var half = a/2;
var multi = half*b;
result += s+' half of A multiplied by B = '+multi+"\n";
a = half;
} // end of loop
console.log(result);
return result;
} // end of function
do1000Times(a,b,s) // execute the function
vs an object with just local parameters doing the same loop
const run1000Times = {
temp : [],
result : '',
run : function(val1,val2,str) {
this.result = '';
for (this.temp.i = 0; this.temp.i < 1000; this.temp.i++) {
this.temp.half = val1/2;
this.temp.multi = this.temp.half*val2;
this.result += str+' half of A multiplied by B = '+this.temp.multi+"\n";
val1 = this.temp.half;
} // end of loop
console.log(this.result);
return this.result;
} // end of run
} // end of object
run1000Times.run(10, 2.33, 'example2') // execute run inside object
A less readable syntax but maybe faster/more efficient because of the absolute array references?
const loopXTimes = {
temp : [],
run : function(val1,val2,str,loop) {
this.temp[3] = ''; // [3] holds result
for (this.temp[0] = 0; this.temp[0] < loop; this.temp[0]++) {
// temp[0] holds iteration count
this.temp[1] = val1/2; // [1] holds result a;
this.temp[2] = this.temp[1]*val2; // [2] holds result b;
this.temp[3] += str+' half of A multiplied by B = '+this.temp[2]+"\n";
val1 = this.temp[1];
} // end of loop
console.log(this.temp[3]);
return this.temp[3];
} // end of run
} // end of object
loopXTimes.run(10, 2.33, 'example3', 1000);
The examples have no differences at all with respect to scope. Both use only local variables. The parameters are also local.
If one function use global variables and the other function use local variables there is no difference in memory usage.
To use constants in comparision < 1000 or variables < loop with loop set to 1000 makes no difference. Javascript internally optimize to whicheffer is the most effective.
To use the newer keywords const or let over var makes coding more specific and safe. It gets not faster or lessen not memory consumtion. The scope is closer with let, but it doesn't make any difference compared to a binding as far as in another object. A binding is just a binding to a variable or a constant - same speed and a memory location of same size (32 bits).
Essentially every variable have exactly the same memory usage of 32 bits. It is how Javascript is implemented to work best in general. Use (time consuming) bit operations to store 32 booleans in a variable if you must, but otherwise just let the few booleans in a program have it's use of 32 bits each. It is the size of a memory location that fit the hardware best. To store more in memory locations you also can look into typed arrays.
In a loop it is no difference to have the bindings into variables in a lot of different objects or to flatten it to have the variables directly in a loop. It is one step bindings in both cases. Javascript optimize by make local declarations to global if nessecary. It also optimize deep dot-referencing to one step bindings.
Sometimes it may be better to reference directly into objects instead of making a a lot of copies by assigning variables. Each copy (instance) requires both space and time. For example passing an object instead of its values is better. Javascript has pass by value meaning object reference is only one value to pass.
The most of time there is no use of try micro-optimize the code because the internal compiler optimization takes care of it.
Now to answer your question: is one local scope property array for temporary results better than many global variables?
Global variables stored in the window object is generally not a good practice. If the window object has to be looped (that I doubt the internal JS do) it takes more time. But the dot-operation (with .key) is still same speed independent of size or where in memory it is. Also indexing (with ['key']) is the same - actually obj['key'] equals obj.key. Everything in Javascript is Object, even arrays!
If you mean global variables in a function compared to store it in an array it has no time or space differences at all when talk about retrieving value from variable compared to indexing or referencing - it is the same. The compiler see those just as bindings to values in memory.
Compared array of size 1000 to have same data in 1000 variables in code has still no memory gains after compilation and optimization. Compiler store variables in a memory chunk (that may be seen as an array).
Consider a function that acts on one element of complex object I'm passing around. I can write it as:
function foo(object) {
bar(object.item)
}
or
function foo(item) {
bar(item);
}
If I have the option, is there any performance benefit to passing just the single element of the object to a function vs passing the whole object and pulling out the pieces I need?
I.e., is it more efficient to call:
foo(object);
and pass along the entire object let foo deal with, or
foo(object.item);
which only passes the single item?
Update: It looks like the terminology I could not find until the comments arrived is whether Javascript is pass-by-reference or pass-by-value.
As objects are passed by reference in Javascript (with some important caveats), it should make no difference how big the object I'm passing is.
Interesting reading:
https://medium.freecodecamp.org/understanding-by-reference-vs-by-value-d49139beb1c4
Object property access is a little bit more expensive than plain value access. (warning, the following snippet will block your browser for a bit, depending on your computer's specs:)
(() => {
const obj = { foo: 'bar' };
const t0 = performance.now();
for (let i = 0; i < 1e9; i++) {
obj.foo;
}
const t1 = performance.now();
const { foo } = obj;
for (let i = 0; i < 1e9; i++) {
foo;
}
const t2 = performance.now();
console.log('Object property access: ' + (t1 - t0));
console.log('Variable access: ' + (t2 - t1));
})();
The difference is tiny, but it's there. When you have obj.prop, the interpreter first has to look up what obj refers to, and then it has to look up the prop property on obj to get to the value. So, it makes sense that it's a bit easier when the value you're looking for is already in a standalone variable - all that's necessary to get to it is for the interpreter to look up that variable.
But, for the example you mention, no matter what, you'll be doing one object lookup, and one plain value lookup:
foo(object); // 1 variable lookup
function foo(object) {
bar(object.item) // 1 object property lookup
}
// vs
foo(object.item); // 1 object property lookup
function foo(item) {
bar(item); // 1 variable lookup
}
It would be different if foo used the .item property more than once. For example, if foo had:
foo(object); // 1 variable lookup
function foo(object) {
bar(object.item) // 1 object property lookup
baz(object.item) // 1 object property lookup
}
that would require two object property lookups, which means it would be (very slightly) more efficient to pass the item alone.
All this said, the difference really is minuscule. As you can see with the snippet, it requires one billion iterations (at least on my machine) to reliably see a difference, and even then, the improvement is only ~5-10% or so, at least for me on Chrome. It's not something worth worrying about in 99% of situations. Code readability is more important.
I was reading David Flanagan's JavaScript: The Definitive Guide, probably the fattest book for JavaScript in the world. When briefly describing array initializers, Flanagan said "The element expressions in an array initializer are evaluated each time the array initializer
is evaluated". What does this means. My practice results made me more confused:
var a = 50;
var b = 70;
var array = [a+b, 50];
console.log (array [0]); //120
a = 60;
console.log (array [0]); //120
var other = array;
console.log (other [0]); //120
I thought the result would be 130 after I change a's value to 60, because the expression is going to be re-evaluated. But it's not that. I know I am completely getting it wrong. Can someone explain what Flanagan is trying to explain in that sentence?
He means that when the array literal expression is ("re"-)evaluated, so will be its contents.
function makeArray() {
return [a];
}
var a = 0;
console.log(makeArray()); // [0]
a = 1;
console.log(makeArray()); // [1]
So, nothing special actually, just default expression behaviour.
You've misquoted the author; what he actually said is
The element expressions in an array initializer are evaluated each time the array initializer is evaluated.
Rather than the term "array initializer", it would be clearer, and more in line with common usage, if he said "array literal". If we adopt the common-sense interpretation of "array initializers" as meaning "initializers for an array-valued variable", then such initializers could be array literals, but could also be any array expression. (Having said that, it does appear that the spec uses the term "array initializer" for "array literal" in Section 12.2.5, so the author's usage is not wrong in that technical sense.) Array literals (basically, anything of the form [...]) can, on the other hand, be used as initializers, but can also be used elsewhere.
What he appears to be trying to say is that an array literal such as
[a]
re-evaluates a each time it itself is re-evaluated, such as when a function is re-executed. If you think about it, that's pretty obvious. It's hard to see how it could work any other way. So the function
function foo(x) { return [x]; }
will return the array [1] when called as foo(1), and the array [2] when called as foo(2), because the array literal [x] is re-evaluated each time the function is called.
This is an entirely different issue from the one that is tripping you up, which is that
var a = 22;
var b = [a];
a = 42;
console.log(b);
does not change b to have the value [42]. This behavior has nothing to do with how array initializers are (re-)evaluated or their component elements are (re-)evaluated. Is has to do with how JavaScript variables and references work. The above would change the value of b if b were storing a dynamic reference to a as its element, but JavaScript has no such notion of dynamically-updatable references. To put it a different way, the console.log(b) line is indeed evaluating b, but that just returns whatever b already is. It does not (re-)evaluate the expression [a] originally used to set b. The fact that b happens to have taken on he value resulting from evaluating [a] is lost immediately after the statement setting the value of b, at which point b now has the value [22].
Consider also the following example, which is completely analogous:
var a = 1, b = 2, c = a + b;
a = 42;
console.log(c);
Here, no-one would expect the expression given as the initial value for c to change when the value of a changes later. c is 3, and it will always be until explicitly re-assigned. In the console(c) line, yes, we are "evaluating" c, but that is merely a matter of retrieving the value of c, not of re-evaluating some expression which happens to have used to assign a value to c in the past. There are some other declarative-style language paradigms where things might behave in that way, but not JavaScript.
Here you assigning the array to array variable and it will store that value until that variable(unless you modify that variable) goes out of scope. In the second statement you're reusing the the same array pointed to by "array" variable. Third statement is just assigning the reference to "array" variable to another variable and access the same element.
Only the first time a+b statement is evaluated and that resulting array is saved as value reference. Last statement is an example of pass by value(Javascript is always pass by value) where copy of "array" variable is created as "other", and "other" also points to same memory reference pointed by "array" variable.
the difference (speed, performace, side effects, ...) between implementations of the for loop:
between
var i;
for(i = 0; i < length; i++){ //Do something}
// more code
and
for(var i = 0; i < length; i++){ //Do something}
// more code
and
for(i = 0; i < length; i++){ //Do something}
// more code
and between
var e;
for( e in array){ //Do something}
// more code
and
for(var e in array){ //Do something}
// more code
and
for(e in array){ //Do something}
// more code
There is no difference.
JavaScript variables have only function scope, and although you can place a var statement in the initialisation part of a for loop in reality the declaration is "hoisted" to the top of the scope such that when your second case examples run they're treated exactly like the first cases.
EDIT: Since you updated the question after I answered, the third syntax that you added where you don't use the var keyword means the variable i (or e) will be created as a global - unless it already exists as a global in which case the existing variable will be overwritten. Global variable access is slower than local variable access.
NOTE: my interpretation of the question is that it is not comparing a standard for loop with the for..in variant, it is just compared the different variable declaration methods with each other for a standard for loop, then doing the same again for a for..in loop.
There is no difference in relation to the declariation of your counter variable..
BUT ALWAYS DECLARE YOUR VARIABLES WITH var
Otherwise they pollute javascript's already dirty global scope...
As far as for...in vs traditional for look here...
(Which is my answer to the duplicate question...)
Yes, there is a difference between for loop and for/in loop in javascript. Here is what is different
consider this array
var myArr = ["a", "b", "c"];
Later, I add an element to this array, but in a different way, like so:
myArr[myArr.length + 1] = "d";
At this point of time, this is what the array looks like, if you console.log it
["c", "b", "a", undefined × 1, "d"]
Now, let us loop through the array using for and for/in loop and see what the difference is:
first, lets try the for loop
for(var i = 0; i != myArr.length; i++) { // note, i used " != " instead of " < ". Yes this is faster.
console.log(myArr[i]);
}
// output will look like this:
// "a"
// "b"
// "c"
// undefined × 1
// "d"
// - This still shows the undefined value in the array.
Now, lets look at the for/in loop
for(key in myArr) {
console.log(myArr[key]);
}
// array will look like:
// "a"
// "b"
// "c"
// "d"
// This will skip the undefined value.
Difference 1: The javascript interpreter will skip all values that are null or undefined when using the for/in loop. Also, the for/in loop will convert all values if it encounters a primitive value, to its equivalent wrapper object. Where as the for loop doesn't do this.
Difference 2: When using the for loop, we declared the variable i within the loop, this variable will be scoped within a function, if the for loop is written within that function. Which means, until the function ends, the variable i is still available, even outside of the for loop, but within that function. Where as, in case of the for/in loop, the scope of the "key" variable dies immediately after the for/in loop stops executing, which means, there is less memory utilization.