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

为什么控制台上的JavaScript变量声明会导致;“未定义”;正在印刷?,javascript,Javascript,我已经阅读了以下SO帖子: 但这些都不能解释为什么当我声明一个变量时,JavaScript控制台会打印未定义的,如下所示: var-a它打印此表达式的结果-它是未定义的。是的,var a本身就是一个有效的表达式 实际上,当您编写var a=3或诸如此类的内容时,为什么console会打印undefined。如果处理了function anyFunctionName(){}语句,它还会打印undefined。事实上,如果存在另一个具有某些“真实”结果的语句,则所有var和function声明

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

但这些都不能解释为什么当我声明一个变量时,JavaScript控制台会打印未定义的,如下所示:

var-a

它打印此表达式的结果-它是
未定义的
。是的,
var a
本身就是一个有效的表达式

实际上,当您编写
var a=3
或诸如此类的内容时,为什么
console
会打印
undefined
。如果处理了
function anyFunctionName(){}
语句,它还会打印
undefined
。事实上,如果存在另一个具有某些“真实”结果的语句,则所有
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
    且其完成值为
    值V
    ,则返回
    值V
  • 如果
    result.type
    normal
    且其完成值为
    ,则返回值
    未定义
现在的问题是,
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)
函数f(){}
var a=5
语句的返回值都是
(正常、空、空)
。因此,脚本最后给出了第一条语句的结果(从脚本的结尾开始,所以从技术上讲,它是最后一条语句),这不是
(正常、空、空)
。这是
a=4
赋值语句的结果,即
4


P.S.S.现在为蛋糕锦上添花:考虑以下内容:

>>> function f() {}
undefined

>>> (function f() {})
function f() {}
区别非常微妙:第一个输入被视为
函数声明
语句,根据这条规则

productionSourceElement:FunctionDeclaration评估为 如下:

  • 返回(正常、空、空)
。。。我们已经知道,当
eval
-ed时,最终将产生
undefined


但是,第二个输入被视为一个函数表达式
,并进行计算。这意味着它将通过
eval
并最终返回控制台(以其格式)。

因为您所做的只是声明存在一个变量-它是什么?一个字符串,一个整数,一个布尔值-我们还不知道-因此
未定义

var a=1;
a
给出:

1
undefined

给出:

1
undefined
在第一种情况下,控制台计算a,以便打印a的值


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

每次计算一行代码时,都会得到一个完成类型/记录
结果
,它有3个属性:
类型
目标
。根据报告:

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

如果
result.type
正常且其完成值为
,则返回值
未定义

事实证明,当您声明变量或函数时,
完成类型是
(正常、空、空)
。由于
结果.type
正常
且值为
,因此它返回值
未定义

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

有关
语句
表达式
的术语,请参阅

有关完成类型的不同值,请参见

如果查看完成类型文档,可以看到空语句
还有一个完成类型
(normal,empty,empty)
(因此它应该返回
undefined
),事实上就是这样。出于同样的原因,
if(x>3){console.log(x)}
也返回
undefined
do{console.log(3);},而(false)
也返回

但是,
(函数f(){})
不会返回
未定义的
,因为它是一个表达式语句

自己测试。以下是更多的例子:

eval('function f(){}');//返回(正常、空、空)、未定义
求值(“;”);//返回(正常、空、空)、未定义
eval('(函数f(){});//(正常、GetValue(exprRef)、空)、ExpresionStatement
函数foo(){
返回4;
}//返回(norma