【问题标题】:Do reserved words need to be quoted when set as property names of JavaScript objects?保留字设置为 JavaScript 对象的属性名时是否需要引用?
【发布时间】:2017-03-05 16:43:00
【问题描述】:

给定一个对象字面量或jQuery(html, attributes) 对象,是否有任何规范声明保留字或未来的保留字必须被引用?

或者,例如,可以将class 设置为对象的属性名称,而不使用引号将属性名称括起来,而这种做法不会违反有关标识符、属性名称或使用保留字的规范?

寻求有关此问题的结论性答案以避免混淆。

let objLit = {
  class: 123,
  var: "abc",
  let: 456,
  const: "def",
  import: 789
}

console.dir(objLit);

jQuery("<div>012</div>", {
  class: "ghi"
})
.appendTo("body");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>

相关:

规格

标识符名称是根据 “Identifiers” section of chapter 5 of the Unicode standard 中给出的语法,有一些小的修改
Identifier 是一个 IdentifierName,不是 ReservedWord

【问题讨论】:

  • @AndrewLi - 答案说 "NOT be used as identifier names"spec 说 PropertyNames 是 "IdentifierNames",所以它是相当混乱。标识符在 ES5 规范中没有很好地描述,但它确实说诸如 “属性名称成为可见的标识符绑定”和 “Object.prototype 的所有属性都作为标识符可见范围” 所以很难说什么是什么?
  • @RobG - 如果属性名称是“标识符”,它显然不能是保留关键字,但 answer 另有说明,并声称 PropertyName 不是标识符
  • @user2357112 MDN 不是规范,ECMAScript® 语言规范在标题中包含名称“规范”。从构成文档的可靠来源寻求有关该问题的说明,说明该语言的使用方式。或者,来自熟悉核心级别语言的作者,甚至是该语言的用户。
  • @guest271314 - 假设他是正确的,它确实如此。对我来说真正的问题不是它是否有效,似乎今天所有的解释器都足够聪明,可以理解花括号中使用的保留关键字不会冲突,但在花括号之外,它总是有风险。规范说对象的 propertyName 可以是字符串、数字或标识符名称,但是将数组、对象或其他任何内容作为键传递也很好,即使它不在规范中。此外,ES6 类的名称似乎是“propertyName”,也应该接受任何东西,但你真的不能这样做class class
  • @adeneo 注意,它在 (6.0) the spec 中:PropertyName 可能是 ComputedPropertyNameComputedPropertyName 可以是 AssignmentExpression,因此允许许多东西作为键。此外,在spec 上,它提到语法是class BindingIdentifier,其中BindingIdentifier is an Identifier 因此不是ReservedWord

标签: javascript language-lawyer ecmascript-5


【解决方案1】:

ECMAScript 5+

不,自 ECMAScript 5 起就不需要引号了。原因如下:

正如您在帖子中提到的,来自ECMAScript® 5.1 Language Specification

7.6标识符名称和标识符

标识符名称是根据 Unicode 标准第 5 章“标识符”部分中给出的语法解释的标记,并进行了一些小的修改。 IdentifierIdentifierName 不是 ReservedWord(请参阅 7.6.1)。

[...]

语法

Identifier ::
  IdentifierName but not ReservedWord

按照规范,ReservedWord 是:

7.6.1保留字

保留字是不能用作IdentifierIdentifierName

语法

ReservedWord :: 
  Keyword
  FutureReservedWord
  NullLiteral
  BooleanLiteral

这包括关键字、未来关键字、null 和布尔文字。完整名单如下:

7.6.1.1关键词

break    do       instanceof typeof
case     else     new        var
catch    finally  return     void
continue for      switch     while
debugger function this       with
default  if       throw 
delete   in       try   

7.6.1.2未来保留字

class enum   extends super
const export import

7.8.1 空文字

null

7.8.2 布尔文字

true
false

以上(第 7.6 节)暗示IdentifierNames 可以是ReservedWords,并且来自object initializers 的规范:

11.1.5 对象初始化器

[...]

语法

ObjectLiteral :
  { }
  { PropertyNameAndValueList }
  { PropertyNameAndValueList , }

PropertyName 在哪里,根据规范:

PropertyName :
  IdentifierName
  StringLiteral
  NumericLiteral

如您所见,PropertyName 可能是IdentifierName,因此允许ReservedWords 是PropertyNames。这最终告诉我们,根据规范,允许将 ReservedWords(例如 classvar)作为 PropertyNames 不加引号,就像字符串文字或数字文字一样。


ECMAScript

要更深入地了解为什么在 ES5 之前的版本中不允许这样做,您必须查看 PropertyName 是如何定义的。根据ECMAScript® 3 Language Specification

PropertyName :
  Identifier
  StringLiteral
  NumericLiteral

如您所见,PropertyNameIdentifer - 而不是 IdentifierName,因此导致 ReservedWords 无法作为 PropertyNames。

【讨论】:

  • 附带说明,JSON 格式要求所有属性名都被引用的原因是该标准是在 ES3 时代制定的,而 Douglas Crockford 不想在 JSON 规范中包含保留字(reference)。
【解决方案2】:

给定一个对象字面量或 jQuery(html、属性)对象,是否有任何规范规定必须引用保留字或将来的保留字?

否(从 ES5 开始)。

spec中对property的定义是任何标识符名称。 class 是一个非常好的标识符名称。

正如其他人在 cmets 中指出的那样,根据规范,对象文字中的属性名称可能是(不带引号的)IdentifierName(除了是字符串等)。 IdentifierName 实际上是任何 Unicode“字母”序列,如 section 7.6 中给出的。

注意

产生的语法错误
const {class} = obj;

不是例外。那不是对象文字,这就是问题所在;这是一个 assignment(或解构类型),它尝试分配一个 variable class。当然,你不能,永远不能,也永远不能拥有以保留字命名的变量

另请参阅this blog post,虽然它不具有权威性,但它是关于 ES5/6/7 的所有事物的可靠、高质量的信息来源。

请注意,在 ES3 中,PropertyName 的定义是 Identifier,而不是 ES5 中的 IdentifierName。这阻止了使用诸如class 之类的属性,因为class 不是标识符。正是这种变化允许使用不带引号的保留字作为对象文字(以及点符号)中的属性。

关于“jQuery 对象”,“jQuery 对象”只是一个普通的旧 JS 对象。你的意思是 DOM 元素 hold 由 jQuery 对象吗?它们是一种原生对象和 JS 对象的混合体。作为 JS 对象,它们可以具有属性。但是,它们不能以对象文字形式编写,因此问题并不真正适用于它们。 (作为原生 (DOM) 对象,它们可以具有属性,JS 规范未涵盖后一种情况。)

【讨论】:

  • 没有说明const {class} = obj; 是一个对象字面量。你在哪里读到的?不,jQuery 示例是这个用户如何产生这个问题的。这是该用户最常看到{class:"someClassName"} 的地方。见stackoverflow.com/a/40208959stackoverflow.com/a/36638058。你真的是冲进来的。也许您会在再次阅读问题以及随附的 cmets 后解决问题。
  • OP 不认为 const {class} = obj; 是一个对象文字 - 你可能把他/她和我混淆了。我意外地将它与 cmets 中的对象文字混淆了。
  • @torazaburo 不要在这里“投反对票”,尽管您当前答案的某些部分显示缺乏实际阅读问题和 cmets?然而,您还没有编辑您的答案。你在讨论中添加了什么? "const {class} = obj;That's not an object literal," OP 是否在实际问题中声明这是一个对象文字?
  • @guest271314 我从来没有说过 OP 说 const {class} = obj; 是一个对象文字。我回答的那部分只是澄清。您希望我如何编辑我的答案?
  • 关于解构赋值的部分是 cmets 讨论的警告,不一定是实际问题的一部分。 jQuery 被用作示例,因为这是该用户使用最多的地方,如果不是专门看到{class:"someClassName"}。解释使用关键字或保留字的注意事项。
【解决方案3】:

这个答案无法与已经给出的答案相提并论,但我还是很乐意加入。

在我的代码中,我更喜欢总是引用键,例如:

var o;

o = {
  "label": "Hello",
  "index": 3
};

这样,奇怪名称或保留关键字的问题甚至不会出现。此外,所有对象文字都以非常接近有效 JSON 的样式编写,因为可以非常快速地完成额外的复制+粘贴到单独的 JSON 文件(反之亦然)。

今天,我认为这是干净代码的必备风格。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 2018-07-19
    • 2014-12-02
    • 2011-09-13
    相关资源
    最近更新 更多