3

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:


  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?

  2. 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:


  1. 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?
  • I'm not sure about your first two questions... not sure how garbage collection works in JS and assume it is environment specific... but for the last question there is no reason for m to point at k... when you assign `prop1:k` in your instantiation of m, you are passing the reference pointer of k to the object m... and then when you override with `var k=0` you are saying that the current variable name k should be associated with a whole new object... saying nothing about it's original reference ...sorry if my answer is confusing I don't think I worded that well... – Leland Richardson Jun 20 '12 at 05:37
  • There is only **one** variable called `k`. Variables name objects. Variables are not objects. –  Jun 20 '12 at 05:42

1 Answers1

3

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:

Community
  • 1
  • 1