为什么控制台上的 JavaScript 变量声明会导致打印“未定义”?

IT技术 javascript
2021-01-21 15:10:00

我已经阅读了以下 SO 帖子:

为什么这段 JavaScript 代码会在控制台上打印“undefined”?

为什么 Chrome 和 FireFox 控制台打印 undefined?

为什么 JS 控制台返回一个额外的 undefined?

但这都没有解释为什么当我如下声明变量时JavaScript 控制台打印undefined

var a;

4个回答

它打印此表达式的结果 - 即undefined. 是的,var a它本身就是一个有效的表达方式。

实际上,您应该对为什么在写作时console打印或类似的东西感到好笑它还打印if语句已处理。事实上,如果有另一个具有“真实”结果的语句,则所有and声明 (!) 语句似乎都被忽略了:undefinedvar a = 3undefinedfunction anyFunctionName() {}varfunction

>>> 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.typenormal并且其完成值为 a value V,则返回value V
  • 如果result.typenormal并且其完成值为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的评估如下:

  • 返回(正常,空,空)。

... 最终会产生undefinedwhen eval-ed,正如我们已经知道的那样。

然而,第二个输入被视为 a Function Expression,它被评估为函数本身这意味着它将被传递eval并最终返回到控制台(以其格式)。

@Rajkumar 好吧,现在我想我找到了一个解释。)
2021-03-15 15:10:00
该行为并非特定于萤火虫。Chrome 控制台甚至 node.js 在遇到变量声明时都会提示打印“未定义”。
2021-03-21 15:10:00
为什么 (var a = 1;) 打印“未定义”而 (a = 1;) 不打印任何内容。第一个是表达式(计算结果为未定义)而第二个甚至不是表达式?
2021-03-24 15:10:00
没错,改了。现在正在寻找这种官方声明。
2021-04-02 15:10:00
添加了一些关于Function Declaration语句的细节- 我最初错过了标准中的那部分,并且想知道为什么它没有被评估为函数本身。但是现在,当我找到了对 和 之间区别的清晰描述时Function Expression,我认为拼图的最后一块就在那里。)
2021-04-06 15:10:00
var a=1;
a

给出:

1

尽管

var a=1;

给出:

undefined

在第一种情况下,控制台评估 a,因此它打印 a 的值

在第二种情况下,控制台不计算 a 的值,而是计算表达式本身。

因为你所做的只是声明有一个变量——它是什么?一个字符串、一个整数、一个布尔值——我们还不知道——因此undefined

Richie:正如我在其他评论中提到的,即使我声明并定义了一个变量,控制台也会打印“未定义”。
2021-03-12 15:10:00
你正在声明一个变量 - var a = '嗨,请为我要存储的东西留出一些内存。-> 在你给它一个值之前它是“未定义的”,因为它不知道它是什么 -> 它是一个变量 - 这是我们给整数、数组、布尔值的通用名称 - 它实际上不是任何东西,直到你给它一个类型或一个值(此时它计算出它的类型)
2021-03-13 15:10:00
它是控制台以及 node.js。并且刚刚意识到我的示例中的变量可能已被提升并被分解为两个单独的语句。
2021-03-15 15:10:00
当您键入 (var a = 1;) 时,在语句执行结束时,变量被赋值为 1,但控制台仍选择显示“未定义”。
2021-03-27 15:10:00
你是直接在控制台打字吗?
2021-04-11 15:10:00

每次评估一行代码时,您都会得到一个完成类型/记录result,它具有 3 个属性:typevaluetarget根据Ecma 规范

如果result.type正常并且其完成值为一个值V,则返回该值V

如果result.type正常且其完成值为empty,则返回该值undefined

事实证明,当您声明变量或函数时,completion typeis (normal,empty,empty)由于result.typeisnormal和 value is empty,它返回 value undefined

但是,当您键入 时a = 3,它是一个赋值表达式,其完成类型是(normal, GetValue(), empty). 所以你只会3在控制台中看到

有关statementand周围的术语expression,请参阅差异语句/表达式

对于补全类型的不同值,请参阅补全类型文档

如果您查看完成类型文档,您会发现空语句;也有一个完成类型(normal, empty, empty)(因此它应该返回undefined),确实如此。出于同样的原因,if (x>3) {console.log(x)}也返回undefineddo {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)