45

The behaviour can be seen in this little snippet (execute it as a global script):

var name = {};
name.FirstName = 'Tom';
alert(name.FirstName);

The alert yields undefined in Chrome but works in IE and Firefox. I also get a weird value when I do

alert(name);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Pialy Tapaswi
  • 521
  • 7
  • 9
  • 3
    `language` attribute is deprecated, use only the `type` attribute. It's also better to use `console.log` instead of the `alert` and use the Chrome Dev. Tools (or FireBug) to read them. And finaly you need to have a doctype on line 1 of your code, a doctype is: ` ` – Wouter J May 09 '12 at 20:37
  • 2
    AFAIK it's more common to use the `var name = {}` syntax too. – Hamish May 09 '12 at 20:39
  • It was just typo ... I entered 'Object' not object. it still throws error in chrome. try the new code in chrome. – Pialy Tapaswi May 09 '12 at 20:56
  • name is a special global variable in browsers, you can't alter it too much... – dandavis Jan 28 '14 at 02:53
  • @dandavis but its not reserved keyword, and only that name variable behaves odd. – user3242837 Jan 28 '14 at 02:56
  • Doesn't have to be a reserved keyword. There are a bunch of special variables like that; for example, assigning to `location` will navigate to a new page. – user2357112 Jan 28 '14 at 02:59
  • reserved or not window.name is assuredly very special. if you set name and go to a different domain, name remains. the way that's wired forces the name property to appear as a normal string, and it cannot be redefined to a different type, just like window.location for example. – dandavis Jan 28 '14 at 02:59
  • 1
    window.name is a special global variable in browsers. See https://developer.mozilla.org/en-US/docs/Web/API/Window.name it assumes the type is a string. If you use typeof to check nString, it is an object. You can run it in a nodejs console and the results is correct then. So it is not a javascript problem. – Chris Li Jan 28 '14 at 03:03
  • Yeah, thanks dandavis, i just came to know that there are other varaibles that are not reserved and yet assumed to behave like reserved. – user3242837 Jan 28 '14 at 03:26
  • @ChrisLi—actually, it is a JavaScript™ "problem", i.e. it's a feature of the *window* host object as implemented in browsers per Mozilla and W3C specifications, it's not part of ECMAScript. – RobG Jan 28 '14 at 03:42
  • @RobG yes, cause ECMAScript is core thing so when it comes to client side in browsers it has window global object and it has these special properties. – user3242837 Jan 28 '14 at 03:53
  • Same as [Why does JavaScript split() produce different output with different variable names?](http://stackoverflow.com/q/9801214/1529630). One should be closed as duplicate of the other. – Oriol Apr 14 '16 at 21:43
  • same thing happens with "status". – Garr Godfrey May 25 '18 at 06:34

4 Answers4

48

window.name has a special purpose, and is supposed to be a string. Chrome seems to explicitly cast it to a string, so var name = {}; actually ends up giving the global variable name (i.e. window.name) a value of "[object Object]". Since it's a primitive, properties (name.FirstName) won't "stick."

To get around this issue, don't use name as a global variable.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
16

Your name variable is actually window.name, because top-level variables declared with var are attached to the global object.

The HTML5 spec requires that window.name is a DOMString. This means that the value of window.name can only be a sequence of characters, not an object.

In Chrome, an attempt to use window.name to store anything except a primitive string will coerce the value to a primitive string. For example:

window.name = {};
window.name === "[object Object]"; // true

You can avoid this problem by using a name variable that is not in the top-level scope:

(function() {
    var name = {};
    // this `name` is not `window.name`
    // because we're not in the top-level scope

    console.log(name);
})();
Ry-
  • 218,210
  • 55
  • 464
  • 476
apsillers
  • 112,806
  • 17
  • 235
  • 239
6

With ES6+, you could write your code as let name or const name. This won't assign it or try to override window.name. More on that here.

let name = {};
name.FirstName = 'Tom';
alert(name.FirstName);
maazadeeb
  • 5,922
  • 2
  • 27
  • 40
2

window.name is used to set the name of the window, and since the window name can only be a string, anything you set to window.name is converted to a string. And strings, as primitive values, cannot have properties. The solution is to use a different variable name or a different scope.

Alternatively, you can use window.name as you like if you have this code first. I don't recommend this at all, but, just as a proof of concept:

(function () {
    var _name;
    window.__defineGetter__('name', function () {
        return _name;
    });
    window.__defineSetter__('name', function (v) {
        _name = v;
    });
})();

Additionally, you should use {} in place of new Object. Besides being more concise, it is also more efficient and more explicit.

st-boost
  • 1,877
  • 1
  • 14
  • 17
  • Or just `delete name;` – Oriol Apr 14 '16 at 21:45
  • 1
    Note that [`__defineGetter__`](//developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/__defineGetter__) and [`__defineSetter__`](//developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/__defineSetter__) are both deprecated. Use [`defineProperty`](//developer.mozilla.org/en-us/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) instead. – Sebastian Simon Oct 20 '21 at 17:52