VaR 提升和重新声明之间的值



在节点环境中运行下面的代码。在浏览器控制台中运行它不允许重新声明变量的变量。

console.log(a);
var a = 5;

根据吊装,上面的代码将看起来像这样

var a = undefined;
console.log(a); // undefined
a = 5;

a变量被提升到文件的顶部。JS 引擎在执行之前为此变量分配内存。问题是为什么下面的代码安慰5而不是未定义。

var a = 5;
console.log(a);
var a = 6;

我正在查看此代码并想象它看起来像这样:

var a = 5;
var a = undefined;
console.log(a); // undefined
a = 6;

我想确定答案而不是猜测。JS引擎足够聪明,可以看到a变量已经被声明,并且在这种情况下会忽略下一个var表达式并重新提升?所以输出应该看起来像:

var a = 5;
console.log(a); // 5
a = 6;

所以就像:

  1. JS引擎第一次看到a变量的声明(在本例中与初始化一起),因此它正在分配内存。
  2. JS引擎第二次看到a变量的声明,但将忽略提升,因为给定名称的变量已经在内存中。

我错了吗?

前言:在现代 JavaScript 中,永远不应该使用var。使用letconst


JavaScript 引擎分两步处理var

  1. 进入全局作用域或函数作用域后,它会处理整个作用域中的每个var,为它们定义初始化的变量,并undefined值。如果一个变量被声明了不止一次var,就好像它被声明了一次一样。

  2. 然后,它开始逐步执行代码。在该分步执行中,var语句(var a = 5中的= 5)上的任何初始值设定项都被视为赋值。因此,在这一点上var a = 5待遇与a = 5完全相同。

所以在你的例子中:

var a = 5;
var a = undefined;
console.log(a); // undefined
a = 6;

就好像你写了这个:

var a = 5;
a = undefined;
console.log(a); // undefined
a = 6;

或者这个:

a = 5;
var a = undefined;
console.log(a); // undefined
a = 6;

或者这个:

a = 5;
a = undefined;
console.log(a); // undefined
var a = 6;

或者这个:

var a;
a = 5;
a = undefined;
console.log(a); // undefined
a = 6;

或者这个:

a = 5;
a = undefined;
console.log(a); // undefined
a = 6;
var a;

甚至这个(但请不要! :-) ):

var a = 5;
var a = undefined;
console.log(a); // undefined
var a = 6;
var a;

也就是说,首先创建所有用var声明的变量(并且只创建一次),然后代码运行,就好像它们上的任何初始值设定项都是赋值一样。


这不是处理letconstclass声明的方式(统称为:词法范围的声明)。首先:同一范围内的多个声明是错误(包括其中一个声明与var,另一个声明与词法范围的声明之一)。第二:它们被提升(在上面的步骤 1 中),但提升的绑定¹ 是未初始化的,直到在分步代码中执行声明,此时它被初始化(使用初始值设定项中的值,或者使用undefined如果只是例如let a;)。从进入范围到初始化绑定点之间的时间称为临时死区。var没有它var因为变量在创建时被初始化(值为undefined),但letconstclass声明可以。


¹ 术语绑定是类变量事物的总称。在代码中:

function example(p) {
var v;
let l;
const c = 42;
function f() {
}
class C {}
}

进入example函数的作用域时创建的绑定包括p(参数)、v(var变量)、l(let变量)、c(const常量)、f(函数声明创建的绑定)和C(class声明创建的绑定)。(注意:函数表达式和class表达式的处理方式略有不同。

最新更新