使用变量“name”无法与JS对象一起使用

45

在这个小片段中可以看到这种行为(将其作为全局脚本执行):

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

在Chrome中,警报会产生 undefined ,但在IE和Firefox中可以正常工作。当我执行以下操作时,我还会得到一个奇怪的值

alert(name);

3
language 属性已经被弃用,请仅使用 type 属性。最好使用 console.log 而不是 alert,并使用 Chrome Dev. Tools(或 FireBug)来读取它们。最后,在代码的第一行上需要有一个 doctype,格式为:<!doctype html> - Wouter J
2
据我所知,使用var name = {}语法更为常见。 - Hamish
name是浏览器中的一个特殊全局变量,你不能太过修改它... - dandavis
1
window.name是浏览器中的一个特殊全局变量。请参见https://developer.mozilla.org/en-US/docs/Web/API/Window.name,它假定类型为字符串。如果您使用typeof检查nString,则它是一个对象。您可以在nodejs控制台中运行它,结果是正确的。因此,这不是JavaScript的问题。 - Chris Li
@RobG 是的,因为ECMAScript是核心内容,所以当它在浏览器的客户端中使用时,它具有window全局对象和这些特殊属性。 - user3242837
显示剩余8条评论
4个回答

48

window.name 有特殊用途,应该是一个字符串。Chrome 显式地将其转为字符串,所以 var name = {}; 实际上为全局变量 name(即 window.name)赋值为 "[object Object]"。由于它是原始值,属性(name.FirstName)不会“坚持住”。

要解决这个问题,不要使用 name 作为全局变量。


1
好的发现...我完全没有注意变量名。 - Felix Kling
1
@FelixKling 我几乎把 name 当作保留字来对待,因为有些主机也会给函数一个 name 属性(我以前就被这个问题咬过),闭包不会将其缩小,等等。 - Dagg Nabbit
是的,就我所记得的,有几个与那个问题有关的问题。 - Felix Kling
FYI,链接已经失效。 - evolutionxbox

16

你的name变量实际上是window.name,因为使用var声明的顶层变量会附加到全局对象上。

HTML5规范要求window.name是一个DOMString。这意味着window.name的值只能是一个字符序列,而不能是一个对象。

在Chrome中,试图使用window.name存储除原始字符串以外的任何内容都将强制将其转换为原始字符串。例如:

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

如果使用一个不在顶层作用域的name变量,就可以避免这个问题:

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

    console.log(name);
})();

6

使用ES6+,您可以将代码编写为let nameconst name。这不会将其分配或尝试覆盖window.name。有关更多信息,请单击此处

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


2

window.name被用来设置窗口的名称,由于窗口名称只能是字符串,所以任何你设置给window.name的内容都会被转换为字符串。而字符串作为原始值,不能有属性。解决方法是使用不同的变量名或不同的作用域。

另外,如果你先使用以下代码,也可以随意使用window.name。我不建议这样做,但只是作为一个概念证明:

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

此外,您应该使用{}代替new Object。除了更加简洁外,它还更加高效和明确。

或者只需 delete name; - Oriol
1
请注意,__defineGetter____defineSetter__ 都已被弃用。请使用 defineProperty 代替。 - Sebastian Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接