为什么此行在javascript中有效?
var a = 0[0];
之后a是undefined。
"0"一个的new Number(0)对象。
0[0]返回一个值
0["toString"]太棒了,谢谢指出。
为什么此行在javascript中有效?
var a = 0[0];
之后a是undefined。
"0"一个的new Number(0)对象。
0[0]返回一个值
0["toString"]太棒了,谢谢指出。
Answers:
当您这样做时0[0],JS解释器将第一个0变成一个Number对象,然后尝试访问该[0]对象的属性undefined。
没有语法错误,因为0[0]在这种情况下语言语法允许属性访问语法。该结构(使用Javascript语法中的术语)为NumericLiteral[NumericLiteral]。
ES5 ECMAScript规范的A.3节中的语言语法的相关部分是:
Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
因此,可以通过此过程遵循语法:
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
而且,类似地在遵循语法之后Expression最终也可以NumericLiteral如此,我们看到这是允许的:
NumericLiteral [ NumericLiteral ]
这意味着这0[0]是语法的允许部分,因此没有SyntaxError。
然后,在运行时,只要您从中读取undefined的源是对象或具有对对象的隐式转换,就可以读取不存在的属性(它将被读取为)。而且,数字文字确实确实具有对对象(Number对象)的隐式转换。
这是Java脚本通常不为人知的功能之一。的类型Number,Boolean和String在Javascript通常内部存储为基元(未完全成熟的对象)。这些是紧凑的,不变的存储表示(可能以这种方式实现以提高实现效率)。但是,Javascript希望您能够将这些原语像具有属性和方法的对象一样对待。因此,如果您尝试访问原语不直接支持的属性或方法,则Javascript会暂时将原语强制转换为适当类型的对象,并将其值设置为原语的值。
当您在诸如的基元上使用类似对象的语法时0[0],解释器会将其识别为对基元的属性访问。它对此的响应是将第一个0数字原语带入一个成熟的Number对象中,然后可以访问该对象[0]。在这种特定情况下,[0]Number对象的属性undefined就是为什么这就是您从中获得的值的原因0[0]。
这是一篇有关将原语自动转换为对象以处理属性的文章:
以下是ECMAScript 5.1规范的相关部分:
如果value为undefinedor null,则抛出TypeError ,否则返回true。

- 令baseReference为评估MemberExpression的结果。
- 令baseValue为GetValue(baseReference)。
- 令propertyNameReference为计算Expression的结果。
- 设propertyNameValue为GetValue(propertyNameReference)。
- 调用CheckObjectCoercible(baseValue)。
- 设propertyNameString为ToString(propertyNameValue)。
- 如果要评估的语法产生包含在严格模式代码中,则使strict为真,否则使strict为假。
- 返回类型为Reference的值,其基值为baseValue,其引用名称为propertyNameString,其strict模式标志为strict。
这个问题的有效部分是上面的步骤5。
这描述了当访问的值是属性引用时,它如何调用ToObject(base)以获取任何原语的对象版本。
介绍如何Boolean,Number与String图元被转换成与[[PrimitiveValue]]内部属性组相应的对象的形式。
作为一个有趣的测试,如果代码是这样的:
var x = null;
var a = x[0];
它仍然不会扔在解析时一个SyntaxError,因为这在技术上是合法的语法,但是当你运行该代码会抛出在运行时类型错误,因为当上述属性存取逻辑应用到的价值x,它会调用CheckObjectCoercible(x)或致电ToObject(x)其如果x为null或,都将引发TypeError undefined。
0[1,2]也有效,是什么意思?(我更新了问题)
null或undefined完全没有问题的属性。
0[2]
1,2,但回报2
像大多数编程语言一样,JS使用语法来解析您的代码并将其转换为可执行形式。如果语法中没有可应用于特定代码块的规则,则会引发SyntaxError。否则,无论是否有意义,该代码均被视为有效。
JS语法的相关部分是
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
由于0[0]符合这些规则,因此被视为有效表达式。是否正确(例如,在运行时不会引发错误)是另外一个故事,但是是的。这就是JS评估像这样的表达式的方式someLiteral[someExpression]:
someExpression(可以是任意复杂的)Number,字符串=> String等)get property使用属性名称result(1)调用result(2)上的操作所以0[0]被解释为
index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result
这是一个有效但不正确的表达式的示例:
null[0]
它可以很好地解析,但是在运行时,解释器在步骤2上失败(因为null无法将其转换为对象),并抛出运行时错误。
var x = null; var a = x[0];不会生成语法错误,但是会在运行时引发TypeError。
0[0]返回一个值而不是未定义
在某些情况下,您可以在Javascript中有效地对数字进行下标:
-> 0['toString']
function toString() { [native code] }
尽管现在还不清楚为什么要这样做,但Javascript中的下标等效于使用点分表示法(尽管点数表示法将您限制为使用标识符作为键)。
(0).toString(不调用函数)相同。这是数字类型的属性。
0属性进行访问,并因为它不存在,undefined是更多的在jfriend00解释是正确的。
0[0]将返回未定义。这可能是因为它会,但它并不一定是这样的
我只想指出,这种有效的语法并不是Javascript独有的。大多数语言都会出现运行时错误或类型错误,但这与语法错误不同。在许多情况下,当另一种语言可能会引发异常,包括对不具有给定名称属性的对象进行下标时,Javascript选择返回未定义。
该语法不知道表达式的类型(即使是简单的表达式,如数字文字),也允许您将任何运算符应用于任何表达式。例如,尝试在Javascript中下标undefined或null引起TypeError。这不是语法错误-如果从不执行此错误(位于if语句的错误一侧),则不会引起任何问题,而语法错误根据定义总是在编译时捕获(eval,Function等) ,全部算作编译)。
语法不仅有效,而且undefined在大多数情况下(即使不是所有理智的情况)也不一定要得到结果。JS是最纯粹的面向对象语言之一。大多数所谓的OO语言都是面向类的,从某种意义上说,一旦创建后就无法更改对象的形式(与类相关),只能更改对象的状态。在JS中,您可以更改状态以及对象的形式,而且您执行此操作的频率超出了您的想象。如果您滥用此功能,则会生成一些相当晦涩的代码。数字是不可变的,因此您无法更改对象本身,而不是状态或形式,因此您可以
0[0] = 1;
这是一个有效的赋值表达式,返回1,但实际上未赋任何值。数字0是不可变的。这本身有点奇怪。您可以有一个有效且正确的(可执行的)声明表达式,该表达式不分配任何内容(*)。但是,数字的类型是易变的对象,因此您可以更改类型,并且更改将沿着原型链向下进行。
Number[0] = 1;
//print 1 to the console
console.log(0[0]);
//will also print 1 to the console because all integers have the same type
console.log(1[0]);
当然,这与理智的使用类别相去甚远,但是指定使用该语言是为了允许这样做,因为在其他情况下,扩展对象功能实际上很有意义。这是jQuery插件如何挂接到jQuery对象中的例子。
(*)实际上确实将值1分配给对象的属性,但是您无法引用该(超然)对象,因此将在nexx GC遍历中将其收集
在JavaScript中,一切都是对象,因此,当解释器对其进行解析时,它将0视为对象,并尝试将0作为属性返回。当您尝试访问true或“”(空字符串)的第0个元素时,也会发生相同的情况。
即使您设置0 [0] = 1,它也会在内存中设置属性及其值,但是当您访问0时,它将被视为数字(此处不要混淆为Object和number。)
true[0]或""[0]