Javascript 对象中的键只能是字符串?

IT技术 javascript
2021-01-22 20:25:14

jshashtable 指出:

JavaScript 的内置对象确实使用方括号表示法提供了哈希表功能,前提是您的键是字符串或数字:

据我所知,键只是字符串,(因为无论如何数字都被强制转换为字符串)。我只是想检查并确保上面所说的是错误的(因为键不能是数字)。

ECMA 标准是否对此有任何说明..

还是特定于浏览器的实现?

6个回答

JavaScript 的内置对象确实使用方括号表示法提供了哈希表功能,前提是您的键是字符串或数字

这似乎是不正确的 -对象键 总是字符串,可能是字符串或(自 ECMAScript 2015 起,又名 ECMA-262 ed 6)符号。但这与方括号属性访问是不同的主题。

请参阅 ECMA-262 ed 3 § 11.2.1(另请参阅ECMAScript 2017(草案)。):

属性通过名称访问,使用点符号:

成员表达式。标识符名称

调用表达式。标识符名称

或括号符号:

成员表达式 [ 表达式 ]

CallExpression [ 表达式 ]

点符号由以下语法转换解释:

成员表达式。标识符名称

其行为与

MemberExpression [ <identifier-name-string> ]

同样

调用表达式。标识符名称

其行为与

CallExpression [ <identifier-name-string> ]

其中<identifier-name-string>是一个字符串文字,在处理 Unicode 转义序列后包含与 IdentifierName 相同的字符序列。

因此,在使用点表示法时,点后的位必须符合 IdentifierName 的标准。但是当使用方括号时,会提供一个表达式,该表达式被计算并解析为一个字符串。

简而言之,提供方括号表示法,以便可以使用表达式访问属性,例如

var y = {};
var x = 'foo';
y[x] = 'foo value';

在上面,x在方括号中提供,因此它被评估,返回字符串'foo'。由于此属性尚不存在y,因此已添加。然后将foo属性y赋值为“foo value”。

一般而言,计算方括号中表达式toString()调用方法。正是该值用作属性名称。

在点属性访问方法中,不评估标识符,因此:

y.bar = 'bar value';

创建bar一个值为的属性bar value

如果要创建数字属性,则:

y[5] = 5;

将评估5,看到它不是一个字符串,调用(或多或少)Number(5).toString()返回字符串5,用于属性名称。然后为它分配值5,这是一个数字。

编辑

这个答案是在 ECMAScript ed3 最新时写的,但是事情已经发生了变化。请参阅后面的参考资料和MDN

@pst:最初的报价来自几年前的我。我在编写它时意识到它不是严格准确的,但我试图避免引用规范以保持简单。然而,它引起了混乱,现在无论如何对我来说看起来都是不可接受的,所以我会改变它。
2021-03-13 20:25:14
可以肯定的是,每当我们执行 array[1] 时,它实际上都转换为 array["1"] ?
2021-03-16 20:25:14
@pst:jshashtable 文档现已更新。我仍然想避免过于详细和推出规范,但我已经消除了字符串/数字属性名称业务,并在对象和原语的总体方向上点头。
2021-03-26 20:25:14
@Pacerier:很好的总结,这正是我需要快速了解的
2021-03-27 20:25:14
+1 但是,该论点(来自引用的引用)无效 - 尽管结论是。CallExpression.Ident is identical to CallExpression["Ident"]并不暗示CallExpression[42] is identical to CallExpression["42"](尽管它是 - 并且规范中有决定性的措辞)。
2021-04-07 20:25:14

你是对的键只能是字符串,而数组中使用的数字键被强制并存储为字符串。

var arr = [true];
arr[0] === true;
arr['0'] = false;
arr[0] === false;

ECMAScript 规范,第 42 页:ECMA-262 脚本第 3 版

生产PropertyName : NumericLiteral评估如下:

  1. 形成 NumericLiteral 的值。
  2. 返回到字符串(结果(1))。
你如何证明数字被强制转换为字符串,而不是相反?
2021-03-27 20:25:14
+1 但是,展示第 5 版中的规则以及在棺材上钉钉子会很好。此外,这不显示/涵盖obj[array]或类似的情况(这是使用规则,而不是语法产生式。)
2021-04-01 20:25:14
这取自 ECMA 脚本规范,v3 - 第 42 页:产品 PropertyName : NumericLiteral 的评估如下: 1. 形成 NumericLiteral 的值。2. 返回 ToString(Result(1))。
2021-04-06 20:25:14
可以肯定的是,每当我们执行 array[1] 时,它实际上都转换为 array["1"] ?
2021-04-09 20:25:14

好吧,这是我的答案——主要是因为我对其他(正确)答案中的引用不满意—— [] 中属性名称的表达式总是被强制转换为字符串,并且这种行为在规范中得到了很好的定义因此,根据对相关引用的解释,它可能会被视为误导和/或不正确。

但是,引用并不假定x[42]x["42"]不同它指出-与其他原语和信息的误导排除-只有字符串和数字作为正常属性解析“散列键”(真正的属性名称),在这个意义上,报价可以说是正确的。

这些规则来自标准 ECMA-262 ECMAScript 语言规范第 5 版(2009 年 12 月)

来自“11.2.1 属性访问器”部分(省略产生式规则):

产生式 MemberExpression : MemberExpression [ Expression ] 的计算方式如下:

  1. 让 baseReference 成为评估 MemberExpression 的结果。
  2. 令 baseValue 为 GetValue(baseReference)。
  3. 让 propertyNameReference 成为计算 Expression 的结果。
  4. 让 propertyNameValue 为 GetValue(propertyNameReference)。
  5. 调用 CheckObjectCoercible(baseValue)。
  6. 令 propertyNameString 为 ToString(propertyNameValue)。
  7. 如果正在评估的语法产生式包含在严格模式代码中,则让 strict 为真,否则让 strict 为假。
  8. 返回一个 Reference 类型的值,其基值为 baseValue,引用名称为 propertyNameString,且其严格模式标志为严格。

快乐编码。

键总是字符串。这意味着您不能使用对象实例的身份作为键。

在 Flash 的 ActionScript 3(与 AS2 不同,使用强运行时类型)中有一个 Dictionary 对象,它对键使用严格的相等比较,因此您可以将对象实例本身用作键(以及数字、字符串等)。

如果您想在 JavaScript 中做同样的事情,那会很困难,因为您必须生成自己唯一的对象 ID 并将它们附加到您想要跟踪的每个对象。有些人建议向 Object 类添加原型函数,但这会不必要地增加每个对象的开销。在任何情况下,您都希望通过函数调用为对象提供可跟踪 ID,该函数调用将递增的静态编号分配给诸如“ __objectid__”之类的唯一属性

然后可以想象使用 Add(key,value) 等方法创建一个类似字典的类,但它必须将字符串、数字和对象存储在三个单独的内部散列中,以确保“3”不会与数字 3 或 id 为 3 的对象。 add 方法必须自动将 分配__objectid__给任何尚未分配 id 的对象类型的键。即便如此,您也无法使用方括号访问字典,除非在 JavaScript 中存在一些我不知道的属性分配挂钩。

这是一个functor Array. 它在使用函数式编程范式时很有用。

javascript:
    alert(["Using  ",window.navigator.userAgent] ); 
    FunctorRA=[]; f=function(){return f}; g=function(x){return x};
    FunctorRA[f]=43;
    FunctorRA[g(function(){})]="generic";
    FunctorRA[g(g)]="idempotent";
    alert(FunctorRA);
    for (i in FunctorRA)
        alert([ "Functor[ ", i,
                "]'s\n\n value is \n\n", FunctorRA[i]].join(""));

显示:

Using  ,Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100423
    Ubuntu/10.04 (lucid) Firefox/3.6.3

一个空alert然后:

Functor[ function () {
    return f;
}]'s

 value is 

43

等等。

注意本:

  • alert( FunctorRA )显示.toString()不枚举非数字索引
  • FunctorRA 是数组“服装”中的通用对象
  • 没有直接的. 语法等价物(即使使用字符串eval强制)在 javascript 中
    看到动态函数名称?有关如何:将冒号嵌入到函数名称中的详细信息,即使它通常是在语法上描述初始值设定项属性、标签、?:(条件表达式)等的分隔符.要求转义所有语法上重要的 JavaScript 字符存在类似的问题代码如(){}\n .,.... []作为一个整体,构造有效地为括号内包含的表达式执行此操作,大概是通过将字符串的评估推迟为 String 类型的对象。这与事实相似43.x=2是禁止的但如果43被表示为通过Number类型的对象(43).x=243["x"]=2(证明:javascript:alert( [ (43).x=2, 43["x"]=2 ] )显示2,2javascript:alert(43.x=2)产生错误)。