属性 个有效名称,属性 个分配和访问 JavaScript

Valid property names, property assignment and access in JavaScript

更新问题

在 Javascript 中,什么是有效的 属性 名称? 属性 赋值的各种方法有何不同? 属性 名称如何影响 属性 访问?

备注

我最初问题的答案(见下文)有助于澄清一些问题,但也打开了一个新的蠕虫罐头。现在我有机会更加熟悉 JavaScript,我 相信 我已经能够想出很多东西了。

因为我很难找到将这些信息整合成一个解释,所以我认为扩展我原来的问题并尝试回答它可能会有所帮助。

原问题

最初,MDN JavaScript guide (object literals) 有一些混淆。具体来说,我想知道为什么他们声称如果 属性 名称不是有效的 JavaScript 标识符,那么它必须用引号引起来。然而,他们提供了示例代码,显示数字 7 可以用作 - 不带引号 - 作为 属性 名称。

事实证明,指南只是遗漏了一个重要部分,Pointy 对其进行了更新(更改以粗体显示):

If the property name would not be a valid JavaScript identifier or number, it must be enclosed in quotes.

我还想知道为什么允许 属性 名称偏离适用于标识符的 "may not start with a digit" 规则。这个问题实际上揭示了我对 属性 名字的完全误解,这促使我做更多的研究。

简答

对象 属性 名称可以是任何 valid identifier, numeric literal, or string literal(包括空字符串)。

话虽如此,关于 JavaScript 属性 名称,需要牢记一些可能令人困惑的错综复杂之处,如下所述。

除非您使用有效(非负整数)数组索引,否则最好将所有数字 属性 名称显式分配为字符串。

负数

看起来像负数的东西实际上是一个表达式 — 属性 名称不支持。

// SyntaxError
const obj = { -12: 'nope' };

幸运的是,括号表示法为我们处理表达式。

// Successful property assignment.
const obj = {};
obj[-12] = 'yup';

类型转换

所有 属性 名称在存储之前都被转换为字符串。

const obj = {
  12: '12'
};

console.log(typeof Object.keys(obj)[0]); // -> string

正在解析

但即使在进行类型转换之前,键也会根据使用的语法进行解析,并转换为十进制文字。

const obj = {
  // Valid string literal
  '022': '022',

  // Interpreted as decimal
  6: '6',

  // Interpreted as floating-point
  .345: '0.345',

  // Interpreted as floating-point
  1.000: '1',

  // Interpreted as floating-point
  8.9890: '8.989',

  // Interpreted as decimal
  000888: '888',

  // Interpreted as octal
  0777: '511',

  // Interpreted as hexadecimal
  0x00111: '273',

  // Interpreted as binary
  0b0011: '3',
};


/* Quoted property name */
console.log(obj['022']); // "022"; as expected
console.log(obj[022]); // undefined; 022 is an octal literal that evaluates to 18 before our lookup ever occurs

/* Valid (non-negative integer) array index */
console.log(obj[6]); // "6"; as expected
console.log(obj['6']); // "6"; as expected

/* Non-valid array index */
console.log(obj[0x00111]); // "273"; we're accessing the property name as it was assigned (before it was parsed and typecasted)
console.log(obj['0x00111']); // undefined; after parsing and typecasting, our property name seems to have disappeared
console.log(obj['273']); // "273"; there it is, we found it using the evaluation of our original assignment

第一个问题的答案:

是的,MDN 指南中给出的声明并非 100% 准确,但在您的日常工作中最好遵循它作为规则。您真的不需要创建数字属性名称。

第二个问题的答案:

A property name may not start with a digit but a property name that is a number without any other characters in its name is fine.

存在此异常是因为名称编号与indexes相同的属性。

让我们试试这个:

var obj = {7: "abc"};
obj[7]; // works fine
obj.7; // gives an error (SyntaxError)

现在尝试对对象调用 Array.push 并观察会发生什么:

Array.prototype.push.call(obj, "xyz");
console.log(obj);
console.log(obj[0]);

// Prints
Object {0: "xyz", 7: "abc", length: 1}
"xyz"

您可以看到几乎没有新属性(一个名称为 0,另一个名称为 length)已添加到对象中。此外,您可以将对象用作数组:

var obj = { "0": "abc", "1": "xyz", length: 2 };

Array.prototype.pop.call(obj); // Returns: "xyz"
Array.prototype.pop.call(obj); // Returns: "abc"

您可以在对象上使用数组的方法,这称为 Duck Typing

数组只不过是具有一些预定义方法的对象。

来自MDN

Array elements are object properties in the same way that length is a property, but trying to access an element of an array with dot notation throws a syntax error, because the property name is not valid. There is nothing special about JavaScript arrays and the properties that cause this. JavaScript properties that begin with a digit cannot be referenced with dot notation and must be accessed using bracket notation.

现在您可以理解为什么 属性 名称的数字是有效的了。这些被称为索引,它们用于 JavaScript 数组。由于 JavaScript 需要与其他语言保持一致,因此数字对 indexes/properties 名称有效。

希望这能说明问题。

这里有一些有趣的文章: