Mic*_* M. 119 javascript
为什么这行在javascript中有效?
var a = 0[0];
Run Code Online (Sandbox Code Playgroud)
在那之后,a
是undefined
.
jfr*_*d00 168
当你这样做时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
Run Code Online (Sandbox Code Playgroud)
因此,人们可以通过这个进程跟随语法:
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
Run Code Online (Sandbox Code Playgroud)
并且,在遵循语法之后,同样Expression
最终也可以NumericLiteral
这样,我们看到这是允许的:
NumericLiteral [ NumericLiteral ]
Run Code Online (Sandbox Code Playgroud)
这意味着这0[0]
是语法的允许部分,因此没有SyntaxError.
然后,在运行时,只要您从中读取undefined
的源是对象或具有对对象的隐式转换,您就可以读取不存在的属性(只会被读取).并且,数字文字确实具有对对象的隐式转换(Number对象).
这是Javascript经常未知的功能之一.的类型Number
,Boolean
和String
在Javascript通常内部存储为基元(未完全成熟的对象).这些是一个紧凑的,不可变的存储表示(可能以这种方式实现了实现效率).但是,Javascript希望您能够将这些原语视为具有属性和方法的对象.因此,如果您尝试访问基元上不直接支持的属性或方法,则Javascript将暂时将基元强制转换为适当类型的对象,并将值设置为基元的值.
当您在基元上使用类似对象的语法时0[0]
,解释器会将其识别为基元上的属性访问.它对此的反应是获取第一个0
数字原语并将其强制转换为一个完整的Number
对象,然后它可以访问该[0]
属性.在这种特定情况下,[0]
Number对象的属性undefined
就是为什么这是你得到的值0[0]
.
这是一篇关于将基元自动转换为对象以处理属性的文章:
以下是ECMAScript 5.1规范的相关部分:
如果value为undefined
或null
,则抛出TypeError ,否则返回true
.
- 让baseReference成为评估MemberExpression的结果.
- 让baseValue为GetValue(baseReference).
- 设propertyNameReference是评估Expression的结果.
- 设propertyNameValue为GetValue(propertyNameReference).
- 调用CheckObjectCoercible(baseValue).
- 设propertyNameString为ToString(propertyNameValue).
- 如果正在评估的语法生成包含在严格模式代码中,则let strict为true,否则let strict为false.
- 返回类型为Reference的值,其基值为baseValue,其引用名称为propertyNameString,其严格模式标志为strict.
该问题的操作部分是上面的步骤#5.
这描述了当被访问的值是属性引用时,它调用ToObject(base)
以获取任何原语的对象版本.
介绍如何Boolean
,Number
与String
图元被转换成与[[PrimitiveValue]]内部属性相应地设置的对象的形式.
作为一个有趣的测试,如果代码是这样的:
var x = null;
var a = x[0];
Run Code Online (Sandbox Code Playgroud)
它仍然不会在解析时抛出一个SyntaxError,因为这是技术上合法的语法,但是当你运行代码时它会在运行时抛出一个TypeError,因为当上面的Property Accessors逻辑应用于它的值时x
,它会调用CheckObjectCoercible(x)
或调用ToObject(x)
哪个如果x
是null
或将抛出TypeError undefined
.
geo*_*org 19
与大多数编程语言一样,JS使用语法来解析代码并将其转换为可执行的形式.如果语法中没有可以应用于特定代码块的规则,则会抛出SyntaxError.否则,代码被认为是有效的,无论它是否有意义.
JS语法的相关部分是
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
Run Code Online (Sandbox Code Playgroud)
由于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
Run Code Online (Sandbox Code Playgroud)
这是一个有效但不正确的表达式的示例:
null[0]
Run Code Online (Sandbox Code Playgroud)
它解析得很好,但在运行时,解释器在第2步失败(因为null
无法转换为对象)并引发运行时错误.
在某些情况下,您可以在Javascript中有效地下标数字:
-> 0['toString']
function toString() { [native code] }
Run Code Online (Sandbox Code Playgroud)
虽然没有立即明白你为什么要这样做,但是在Javascript中下标相当于使用点分表示法(尽管点符号限制了你使用标识符作为键).
我只想指出,这是有效的语法并不是Javascript独有的.大多数语言都会出现运行时错误或类型错误,但这与语法错误不同.Javascript选择在许多情况下返回undefined,其中另一种语言可能引发异常,包括在订阅没有给定名称属性的对象时.
语法不知道表达式的类型(即使是像数字文字这样的简单表达式),也允许您将任何运算符应用于任何表达式.例如,尝试下标undefined
或null
导致TypeError
Javascript.这不是语法错误 - 如果从未执行过(在if语句的错误一侧),它不会导致任何问题,而语法错误根据定义总是在编译时捕获(eval,Function等) ,都算作编译).
因为它是有效的语法,甚至是有效的代码来解释.您可以尝试访问任何对象的任何属性(在这种情况下,0将被强制转换为Number对象),如果存在,它将为您提供值,否则为undefined.但是,尝试访问未定义的属性不起作用,因此0 [0] [0]将导致运行时错误.尽管如此,这仍将被归类为有效语法.什么是有效语法和不会导致运行时/编译时错误的区别.
归档时间: |
|
查看次数: |
6639 次 |
最近记录: |