我已经阅读了以下 SO 帖子:
为什么这段 JavaScript 代码会在控制台上打印“undefined”?
为什么 Chrome 和 FireFox 控制台打印 undefined?
但这都没有解释为什么当我如下声明变量时JavaScript 控制台打印undefined:
var a;
我已经阅读了以下 SO 帖子:
为什么这段 JavaScript 代码会在控制台上打印“undefined”?
为什么 Chrome 和 FireFox 控制台打印 undefined?
但这都没有解释为什么当我如下声明变量时JavaScript 控制台打印undefined:
var a;
它打印此表达式的结果 - 即undefined
. 是的,var a
它本身就是一个有效的表达方式。
实际上,您应该对为什么在写作时console
打印或类似的东西感到好笑。它还打印if语句已处理。事实上,如果有另一个具有“真实”结果的语句,则所有and声明 (!) 语句似乎都被忽略了:undefined
var a = 3
undefined
function anyFunctionName() {}
var
function
>>> var a = 3;
undefined
>>> var a = 3; a = 4;
4
>>> var a = 3; a = 4; var a = 5; function f() {};
4 // !!!
现在,我想背后的真正原因是行为的eval
语句,描述在这里:
- 让
result
成为评估程序的结果prog
。- 如果
result.type
是normal
并且其完成值为 avalue V
,则返回value V
。- 如果
result.type
是normal
并且其完成值为empty
,则返回该值undefined
。
那么现在的问题是,var a = 4
语句返回什么?猜猜看:不是 4。
生产VariableStatement : var VariableDeclarationList; 评估如下:
- 评估 VariableDeclarationList。
- 返回(正常,空,空)。
现在最有趣的部分是:在最后一个例子中发生了什么,为什么结果是 4?本节对此进行了解释:
生产程序:SourceElements的评估如下:
- 让 result 是评估 SourceElements 的结果。
[...]
生产SourceElements : SourceElements *SourceElement* 评估如下:
- 让 headResult 成为评估 SourceElements 的结果。
- 如果 headResult 是突然完成,则返回 headResult。
- 让tailResult 是评估SourceElement 的结果。
- 如果 tailResult.value 为空,则让 V = headResult.value,否则让 V = > tailResult.value。
- 返回(tailResult.type,V,tailResult.target)
双方function f() {}
并var a = 5
声明“返回值是(normal, empty, empty)
。所以脚本最终给出了第一个语句的结果(从脚本的末尾开始,所以从技术上讲它是最后一个)不是(normal, empty, empty)
. 那是a = 4
赋值语句的结果- 即4
.
PS 现在让我们锦上添花:考虑以下几点:
>>> function f() {}
undefined
>>> (function f() {})
function f() {}
区别非常微妙:第一个输入被视为一个Function Declaration
语句,根据此规则......
生产SourceElement : FunctionDeclaration的评估如下:
- 返回(正常,空,空)。
... 最终会产生undefined
when eval
-ed,正如我们已经知道的那样。
然而,第二个输入被视为 a Function Expression
,它被评估为函数本身。这意味着它将被传递eval
并最终返回到控制台(以其格式)。
var a=1;
a
给出:
1
尽管
var a=1;
给出:
undefined
在第一种情况下,控制台评估 a,因此它打印 a 的值
在第二种情况下,控制台不计算 a 的值,而是计算表达式本身。
因为你所做的只是声明有一个变量——它是什么?一个字符串、一个整数、一个布尔值——我们还不知道——因此undefined
每次评估一行代码时,您都会得到一个完成类型/记录result
,它具有 3 个属性:type
、value
和target
。根据Ecma 规范:
如果
result.type
正常并且其完成值为一个值V
,则返回该值V
。
如果
result.type
正常且其完成值为empty
,则返回该值undefined
。
事实证明,当您声明变量或函数时,completion type
is (normal,empty,empty)
。由于result.type
isnormal
和 value is empty
,它返回 value undefined
。
但是,当您键入 时a = 3
,它是一个赋值表达式,其完成类型是(normal, GetValue(), empty)
. 所以你只会3
在控制台中看到。
有关statement
and周围的术语expression
,请参阅差异语句/表达式。
对于补全类型的不同值,请参阅补全类型文档。
如果您查看完成类型文档,您会发现空语句;
也有一个完成类型(normal, empty, empty)
(因此它应该返回undefined
),确实如此。出于同样的原因,if (x>3) {console.log(x)}
也返回undefined
和do {console.log(3);} while (false)
太。
但是,(function f(){})
不返回,undefined
因为它是一个表达式语句。
自己测试。以下是更多示例:
eval('function f(){}'); // Return (normal, empty, empty), undefined
eval(';'); // Return (normal, empty, empty), undefined
eval('(function f(){})'); // (normal, GetValue(exprRef), empty), ExpresionStatement
function foo() {
return 4;
} // Return (normal, empty, empty), undefined
foo(); // (return, 4, empty), 4
eval('function foo() {return 5;}'); // Return (normal, empty, empty), undefined
eval('foo();'); // (return, 4, empty), 4
let x = 4; // (normal, empty, empty), undefined
if (x > 3) {
console.log(x);
} // (normal, empty, empty), undefined
console.log(6); // (normal, empty, empty), undefined
eval('let x = 4; if (x>3) {console.log(x)}'); // undefined
let y = 5; // (normal, empty, empty), undefined
do {
console.log(3);
y++;
} while (y < 8); // this returns y, can you explain why?
do {
console.log(3);
} while (false); // undefined since (normal, empty, empty)