1

I ran into an interesting issue the other day and was wondering if someone could shed light on why this is happening. Here is what I am doing (for the purposes of this example I have dumbed down the example somewhat):

  • I am creating a globally scoped variable using the square bracket notation and assigning it a value.
  • Later I declare a var with the same name as the one I just created above. Note I am not assigning a value. Since this is a redeclaration of the same variable the old value should not be overriden as described here: http://www.w3schools.com/js/js_variables.asp

    //create global variable with square bracket notation
    window['y'] = 'old';
    
    //redeclaration of the same variable
    var y;
    
    if (!y) y = 'new';
    
    alert(y); //shows New instead of Old
    
  • The problem is that the old value actually does get overriden and in the above eg. the alert shows 'new' instead of 'old'. Why ?

I guess another way to state my question is how is the above code different in terms of semantics from the code below:

//create global variable 
var y = 'old';

//redeclaration of the same variable
var y;

if (!y) y = 'new';

alert(y); //shows Old

Update 1 : Based on the some of the comments and answers I am rephrasing the example to be more reflective of my original problem.

Create 2 javascript files with the following content : Script1

//create global variable with square bracket notation
window['y'] = 'old';

Script2

//redeclaration of the same variable
var y;

if (!y) y = 'new';

alert(y); //shows New instead of Old in IE

Include these 2 files in your html file

<html>
 <head></head>
 <body>

  <script type="text/javascript" src="my.js"></script>
  <script type="text/javascript" src="my2.js"></script>

 </body>
</html>

Opening this page in Firefox and Chrome alerts 'old' which is the expected behavior. However in IE 8 the page will actually alert 'new'

Update 2 question moved here : Redeclared javascript global variable overrides old value in IE

Community
  • 1
  • 1
Yousuf Haider
  • 178
  • 2
  • 9

4 Answers4

0

When you redeclared y with var y;, it's now undefined, so if(!undefined) evaluates to true.

Add another alert in your example to see this:

//create global variable with square bracket notation
window['y'] = 'old';

//redeclaration of the same variable
var y;
alert(y); //undefined

if (!y) y = 'new';

alert(y); // new

var won't initialize a variable twice, but it will overwrite one not initialized the first time (because it's a new, more local variable), which the window['y'] style does, adding it to the window object. Take this for example:

//create global variable with square bracket notation
window['y'] = 'old';

//redeclaration of the same variable
var y;
alert(y); //undefined

alert(window.y); //old

if (!y) y = 'new';

alert(y); //shows New instead of Old
alert(window.y);​ //still old
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • If that was true why did the second snippet of code not do the same thing. The second snippet of code alerts 'old' instead of 'new' – Yousuf Haider Apr 14 '10 at 02:05
  • 1
    I am trying to understand what you mean by "var won't initialize a variable twice, but it will overwrite one not initialized the first time, which the window['y'] style does, adding it to the window object. " Does this mean that window.y and y are different objects. I thought (incorrectly maybe) that doing window.y or window['y'] meant creating a global variable called y. – Yousuf Haider Apr 14 '10 at 02:12
  • @Yousuf - That's the difference, `var y` is not the same as `window.y`, they are separate variables, the `var y` being the more local of the two in the scope. – Nick Craver Apr 14 '10 at 02:13
  • @Nick - So what you're saying is that creating a property on the Window object is not equivalent to declaring a global variable. If that is the case then can properties declared on the window object (for eg. window.y) be accessed directly or do you have to use window.y to refer to them. – Yousuf Haider Apr 14 '10 at 02:17
  • 1
    @Yousuf - You can access it directly, like this: `window['y'] = 'new'; alert(y);` **provided that** there isn't a more local variable with the same name, then you'll get that local variable instead. ​ – Nick Craver Apr 14 '10 at 02:20
  • Aah! Is there some place where this sort of thing is documented in detail. Thanks for the answers. – Yousuf Haider Apr 14 '10 at 02:22
  • 1
    @Yousuf - There is the spec itself (depending on which version you are running, depends on the browser)...but I'd suggest this for a more practical description of various cases like you've run into here: http://www.digital-web.com/articles/scope_in_javascript/ – Nick Craver Apr 14 '10 at 02:24
0

You cannot "redeclare" variables like that within the same scope in JS.

var x = "foo"
function a()
{
  alert(x); // undefined
  var x;
}

In function a, the variable x is local because it has var x. It doesn't matter if it comes before or after the usage.

Likewise:

function b()
{
  var z = 1;
  if (true)
  {
    var z = 2;
  }
  alert(z); // 2
}

because there is no such thing as "block" scope either.

Matthew
  • 47,584
  • 11
  • 86
  • 98
  • The last statement is not entirely correct, you can use `let()` to get block scoping. – Nick Craver Apr 14 '10 at 02:16
  • You can redeclare it, if the redeclaration occurs at the same scope level. `var x = "foo"; var x; alert(x);` – Matthew Flaschen Apr 14 '10 at 02:17
  • @Nick, true, but I'm limiting myself to the subset of JavaScript as implemented by all major browsers. @Matthew, what do you expect that to display? – Matthew Apr 14 '10 at 02:36
  • @Nick, `let` is a proprietary Mozilla extension, and it will work only on their *JavaScript (TM) 1.7* engines (SpiderMonkey, Rhino) – Christian C. Salvadó Apr 14 '10 at 02:41
  • @CMS - I wouldn't call it "proprietary" (as it's in the 1.7 spec), Mozilla officially manages javascript...granted their engines typically support new specs before others or this same reason, as is the case here. – Nick Craver Apr 14 '10 at 02:47
  • @Nick, I call it proprietary because it isn't part of the ECMAScript Specification, and we will probably never see those language extensions implemented on other engines like JavaScriptCore (*Safari*), V8 (*Chrome*), Carakan (*Opera*), JScript (*IE*) etc... – Christian C. Salvadó Apr 14 '10 at 04:08
  • @CMS - I see your point...though forgive me in the case of `let()` if I hope you're wrong :) There are a lot of tricky corner cases I've seen some of these additions help the readability/simplicity quite a bit. – Nick Craver Apr 14 '10 at 10:05
0

The var statement is subject of hoisting, this means that when the code enters in execution context (just before the actual runtime), the var and function statements are made available to its enclosing scope.

Your code actually gets evaluated as this:

First example:

var y;
window['y'] = 'old';

if (!y) y = 'new';

alert(y);

Second example:

var y;
y = 'old';

if (!y) y = 'new';

alert(y);

With the var statement hoisted, you see actual behavior that the code is having.

See also:

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
0

? I just tested your code and it shows "old", and I've tested FF, Chrome, Safari (PC), and IE8.

Look here: http://jsbin.com/ifare/edit

RussellUresti
  • 6,211
  • 4
  • 28
  • 26
  • 2
    Yes, if the first snippet is run at the global scope level, `window['y']` is equivalent to `var y`, so it does alert old. The jsfiddle is *not* run at the global scope, but rather in a function. Probably Yousuf's original code was in a function too. See view-source:http://fiddle.jshell.net/yaQYn/show/light/ – Matthew Flaschen Apr 14 '10 at 02:28
  • why is doing window['y']='old' different when doing it inside a function as opposed to in the global scope ? – Yousuf Haider Apr 14 '10 at 02:37
  • Yousuf, `window['y']` is the same. It's the `var y` that's different (in a function, `var y` creates a new variable that hides the global unless you use `window`) – Matthew Flaschen Apr 14 '10 at 02:43
  • It's weird that jsFiddle gets you "new". I created just a plain HTML page locally to test this, and I still get "old" when it's just straight from a page. – RussellUresti Apr 14 '10 at 02:48
  • @Matthew - Right, but var y was being declared directly inside a script file. It was not inside a function. That is the point I am trying to make. Since it wasn't inside a function then why is it overriding the old value (since it should be treated as a redeclaration, unless based on Nick's answer those are 2 different variables) – Yousuf Haider Apr 14 '10 at 02:48
  • Yousuf, if you run your top snippet (from the question) as is in a script file, it will alert old. – Matthew Flaschen Apr 14 '10 at 02:58