如果在声明变量之前使用了变量,为啥不会抛出 ReferenceError?

Posted

技术标签:

【中文标题】如果在声明变量之前使用了变量,为啥不会抛出 ReferenceError?【英文标题】:Why is no ReferenceError being thrown if a variable is used before it’s declared?如果在声明变量之前使用了变量,为什么不会抛出 ReferenceError? 【发布时间】:2016-05-30 03:29:07 【问题描述】:

我正在努力思考 javascript 中引发的引用错误的行为。

在下面的例子中,ReferenceError 在第二行被抛出,执行中断:

var obj = ;
obj.func1 = func2;

alert('Completed');

而在本例中,代码成功完成,尽管obj.func1 仍然是undefined

var obj = ;
obj.func1 = func2;

var func2 = function() 
    alert('func2');
;

alert('Completed');

我的假设是同样会在第二行引发错误,如果不是这种情况,我本来希望 obj.func1 正确引用 func2,但我已经加倍了盲目的。那么这里到底发生了什么?

【问题讨论】:

Function Hoisting 和 Variable Hoisting @epascarello:没有函数表达式的函数提升;只有函数 statements 被提升。这是var吊装。 【参考方案1】:

var 被吊起;该变量存在于整个当前范围内。因此,第二个例子等价于:

var obj;
var func2;

obj = ;
obj.func1 = func2;
func2 = function() 
    alert('func2');


alert('Completed');

因此,当您执行分配时,名称 func2 是已知的,但 undefined。在第一个例子中,它是未知的,它引发了ReferenceError

【讨论】:

【参考方案2】:

这是由于 Javascript 变量声明“提升”。

var 声明的变量在函数中随处可见,因此没有Reference Error。但是,在您执行初始化它的语句之前,它实际上并没有收到它的值。所以你的第二个例子相当于:

var func2;
var obj = ;
obj.func1 = func2;

func2 = function() 
    alert('func2');
;

alert('Completed');

在这个重写中,当你对obj.func1进行赋值时,你可以看到变量存在。但是由于它还没有值,所以您将undefined 分配给obj.func1。稍后分配给func2 不会改变这一点。

【讨论】:

obj 的初始化与它的声明有什么关系?我理解,因为无论如何它都会立即发生,没有实际区别,但这是直译吗? 他直到 obj 被初始化后才引用它,因此在声明期间或之后初始化它实际上没有区别。所以我没有费心重写那部分,因为它与问题无关。 我想我只是担心你的例子是否有点模糊了行为,如果这个想法是 declarations 专门被提升。 只有在声明之前尝试使用变量时,声明和初始化之间的区别才有意义。如果所有的用途都在后面,没有区别,所以没有必要显示重写。【参考方案3】:

您的 func2 变量不可见。这就是 obj.func1 保持未定义的原因。

var obj = ;
var func2 = function() 
    alert('func2');
    return "Test";
;
    
obj.func1 = func2;
   
alert('Completed');

【讨论】:

我很清楚在分配 func1 之前定义 func2 会解决错误。这不是一个真正的问题,只是我在修修补补时发现的一些奇怪的东西。

以上是关于如果在声明变量之前使用了变量,为啥不会抛出 ReferenceError?的主要内容,如果未能解决你的问题,请参考以下文章

为啥@interface 中声明的变量中的值不会在 XCTest 中的方法之间持续存在?

ECMAScript 5 严格模式

为啥不能在用 let 和 const 声明变量之前进行赋值? [复制]

JavaScript 中对变量和函数声明的“提前(hoist)”的那些事儿

为啥声明表变量与临时表相比非常慢?

在switch语句中声明变量[重复]