15

我期待 JavaScript 将具有重复属性的对象视为无效而拒绝,但在某些情况下它会接受它们。

{"a":4,"a":5}导致SyntaxError至少在 Firefox 和 Chrome 中,由于属性a被定义了两次,这似乎很明显。

然而({"a":4,"a":5}),评估得很好,并{"a":5}在 Firefox 和 Chrome 中产生了一个对象。

为什么接受带括号的表达式?

总结回答:第一个例子根本不是一个对象的构造,而是一个标记语句块。对象中的重复属性完全有效,在这种情况下最后一个定义获胜。

非常感谢你的回答!

4

6 回答 6

5

在 ECMAScript 3 中,在对象字面量中声明重复属性是完全合法的;你得到的SyntaxError可能来自于你使用对象文字作为语句的事实,由于与块语句()混淆,这是不可能的{ doSomething(); }

如果您希望将此报告为错误,您可能需要切换到 ECMAScript 5 的严格模式:https ://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode 。

于 2012-11-08T09:41:50.933 回答
4

如果您将其分配给变量,则您所说的没有问题,但是,如果您不这样做,则会收到您提到的错误。从语法的角度来看,这一切都不同。

当您将任何结构包装在括号中时,您会导致该语法被评估为表达式,其结果存储为临时变量。我在 Firefox 中不这样做时得到的错误是unexpected labelinvalid label,因此似乎没有赋值或括号,此对象构造不被视为对象构造 - 相反,它被视为具有多个标签语句的块非法定义:

{
  a: function(){
    alert('a');
  },
  b: function(){
    alert('b');
  }
}

上面的内容作为一个对象应该是完全可以接受的,但是如果您在没有将其分配给某种形式的变量或使用括号对其进行评估的情况下对其进行评估,则会出现类似的错误。简单地说,属性名称的重复不会导致错误:)

基本上想象你的第一个例子,但像这样:

function (){
  "a": 4,
  "b": 5
}

这些浏览器大致就是这样对待它的,现在这显然是非法的 javascript 语法......而以前并不那么明显。

于 2012-11-08T09:43:20.463 回答
4

在第一个表示法(无括号)中,javascript 语法是模棱两可的。来自ecmascript 规范

ExpressionStatement不能以左大括号开头,因为这可能会使它与Block模棱两可。

一个基本上是对里面的所有语句求值,相当于求值"a":4,"a":5哪个是无效的JS,实际上返回相同的SyntaxErrorUnexpected token :

将该代码包装在括号中(或者,更确切地说,分组运算符)消除了这种歧义,因为赋值表达式不能跟在块语句后面:

var test = {"a":"a","a":"b"}; //test.a === "b"

此外,任何不能与块语句一起使用的运算符或表达式都可以消除这种歧义。几乎没有想到一个实际场景,也许如果您想将对象文字作为条件运算符的一部分返回?

//this *could* come out of a JS minifier:
return x ? (foo(),{"a":"b"}) : (bar(), {"b":"a"});
于 2012-11-08T10:46:44.173 回答
0

这不是错误,您只是用另一个覆盖值

于 2012-11-08T09:43:02.347 回答
0

我猜测(虽然不确定)这是一个错误,因为 Firefox 和 Chrome 的 JS 解析器处理语句和表达式的方式不同。所以因为它第二次被括号括起来,所以它被认为是一个表达式。由于它在表达式中寻找较少的信息,它可以忽略错误的值。你会看到,如果你这样做...

var a = {'a': 5, 'a': 4};
console.log(a);

它工作正常!还要注意它在语句的右侧,暗示它是一个表达式。

于 2012-11-08T09:45:00.767 回答
0

为什么不应该被接受?您只是在覆盖这些值。我认为这是一个功能,而不是一个错误。它在各种浏览器上对我来说都很好:http: //jsbin.com/oculon/1/edit 这就像写作

var a;

a = 4;
a = 5;

alert(a);
于 2012-11-08T09:35:30.377 回答