深入理解JS:var、let、const的异同

2022-12-20 0 779

1.前言

var、let 和 const 都是 JavaScript 中用以新闻稿表达式的URL,因此 let 和 const URL是在 ES6 中才追加的。难道都是用以新闻稿表达式的,那它间有甚么差别呢?让他们来一探到底。

2.var 与 let 的差别

(1)返回值

用 var 新闻稿的表达式的返回值是它现阶段的继续执行语句,即假如是在任何人表达式外边,则是自上而下继续执行语句,假如在表达式里头,则是现阶段表达式继续执行语句。换句话说,var 新闻稿的表达式的返回值根本无法是自上而下或是整座表达式块的。

而 let 新闻稿的表达式的返回值则是它现阶段所处标识符块,即它的返回值既能是自上而下或是整座表达式块,也能是 if、while、switch等用{}限量发行的标识符块。

除此之外,var 和 let 的返回值准则都是那样的,其新闻稿的表达式只在其新闻稿的块或子块中需用。

实例标识符:

function varTest() { var a = 1; { var a = 2; // 表达式块中,同一表达式 console.log(a); // 2 } console.log(a); // 2 } function letTest() { let a = 1; { let a = 2; // 标识符块中,捷伊表达式 console.log(a); // 2 } console.log(a); // 1 } varTest(); letTest();

从上述实例中能看出,let 新闻稿的表达式的返回值能比 var 新闻稿的表达式的返回值有更小的限量发行范围,更具灵活。

(2)重复新闻稿

var 允许在同一返回值中重复新闻稿,而 let 不允许在同一返回值中重复新闻稿,否则将抛出异常。

var 相关实例标识符:

vara =1; var a = 2; console.log(a) // 2 function test() { var a = 3; var a = 4; console.log(a) // 4 } test()

let 相关实例标识符:

if(false) { let a = 1; let a = 2; // SyntaxError: Identifier a has already been declared } switch(index) {case 0: let a = 1; break; default: let a = 2; // SyntaxError: Identifier a has already been declared break; }

从上述实例中能看出,let 新闻稿的重复性检查是发生在词法分析阶段,也就是在标识符正式开始继续执行之前就会进行检查。

(3)绑定自上而下对象

var 在自上而下环境新闻稿表达式,会在自上而下对象里新建一个属性,而 let 在自上而下环境新闻稿表达式,则不会在自上而下对象里新建一个属性。

实例标识符:

var foo = global let bar = global console.log(this.foo) // global console.log(this.bar) // undefined

那这里就一个疑问, let 在自上而下环境新闻稿表达式不在自上而下对象的属性中,那它是保存在哪的呢?

var foo = global let bar = global function test() {} console.dir(test)

在Chrome浏览器的控制台中,通过继续执行上述标识符,查看 test 表达式的返回值链,其结果如图:

深入理解JS:var、let、const的异同

由上图可知,let 在自上而下环境新闻稿表达式 bar 保存在[[Scopes]][0]: Script这个表达式对象的属性中,而[[Scopes]][1]: Global就是他们常说的自上而下对象。

(4)表达式提升与暂存死区

var 新闻稿表达式存在表达式提升,如何认知表达式提升呢?

要解释清楚这个,就要涉及到继续执行语句和表达式对象。

在 JavaScript 标识符运行时,解释继续执行自上而下标识符、调用表达式或使用 eval 表达式继续执行一个字符串表达式都会创建并进入一个捷伊继续执行环境,而这个继续执行环境被称之为继续执行语句。因此继续执行语句有三类:自上而下继续执行语句、表达式继续执行语句、eval 表达式继续执行语句。

继续执行语句能认知为一个抽象的对象,如下图:

深入理解JS:var、let、const的异同

Variable object:表达式对象,用于存储被定义在继续执行语句中的表达式 (variables) 和表达式新闻稿 (function declarations) 。

Scope chain:返回值链,是一个对象列表 (list of objects) ,用以检索语句标识符中出现的标识符 (identifiers) 。

thisValue:this 指针,是一个与继续执行语句相关的特殊对象,也被称之为语句对象。

一个继续执行语句的生命周期能分为三个阶段:创建、继续执行、释放。如下图:

深入理解JS:var、let、const的异同

而所有使用 var 新闻稿的表达式都会在继续执行语句的创建阶段时作为表达式对象的属性被创建并初始化,这样才能保证在继续执行阶段能通过标识符在表达式对象里找到对应表达式进行赋值操作等。

而用 var 新闻稿的表达式构建表达式对象时进行的操作如下:

由名称和对应值(undefined)组成一个表达式对象的属性被创建(创建并初始化)假如表达式名称跟已经新闻稿的形式参数或表达式相同,则表达式新闻稿不会干扰已经存在的这类属性。

上述过程就是他们所谓的“表达式提升”,这也就能解释为甚么表达式能在新闻稿之前使用,因为使用是在继续执行阶段,而在此之前的创建阶段就已经将新闻稿的表达式添加到了表达式对象中,所以继续执行阶段通过标识符能在表达式对象中查找到,也就不会报错。

实例标识符:

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

let 新闻稿表达式存在暂存死区,如何认知暂存死区呢?

其实 let 也存在与 var 类似的“表达式提升”过程,但与 var 不同的是其在继续执行语句的创建阶段,只会创建表达式而不会被初始化(undefined),因此 ES6 规定了其初始化过程是在继续执行语句的继续执行阶段(即直到它的定义被继续执行时才初始化),使用未被初始化的表达式将会报错。

let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the valueundefined when the LexicalBinding is evaluated.

在表达式初始化前访问该表达式会导致 ReferenceError,因此从进入返回值创建表达式,到表达式开始可被访问的一段时间(过程),就称为暂存死区(Temporal Dead Zone)。

实例标识符 1:

console.log(bar); // undefined console.log(foo);// ReferenceError: foo is not defined var bar = 1; let foo = 2;

实例标识符 2:

var foo = 33; { letfoo = (foo +55); // ReferenceError: foo is not defined }

注:首先,需要分清表达式的创建、初始化、赋值是三个不同的过程。除此之外,从 ES5 开始用词法环境(Lexical Environment)替代了 ES3 中的表达式对象(Variable object)来管理静态返回值,但作用是相同的。为了方便认知,上述讲解中仍保留使用表达式对象来进行描述。

小结

var 新闻稿的表达式在继续执行语句创建阶段就会被「创建」和「初始化」,因此对于继续执行阶段来说,能在新闻稿之前使用。let 新闻稿的表达式在继续执行语句创建阶段只会被「创建」而不会被「初始化」,因此对于继续执行阶段来说,假如在其定义继续执行前使用,相当于使用了未被初始化的表达式,会报错。

3.let 与 const 分野

const 与 let 很类似,都具有上面提到的 let 的特性,唯一差别就在于 const 新闻稿的是一个只读表达式,新闻稿之后不允许改变其值。因此,const 一旦新闻稿必须初始化,否则会报错。

实例标识符:

let a; const b = “constant” a = “variable” b = change // TypeError: Assignment to constant variable

如何认知新闻稿之后不允许改变其值?

其实 const 其实保证的不是表达式的值不变,而是保证表达式指向的内存地址所保存的数据不允许改动(即栈内存在的值和地址)。

JavaScript 的数据类型分为两类:原始值类型和对象(Object类型)。

对于原始值类型(undefined、null、true/false、number、string),值就保存在表达式指向的那个内存地址(在栈中),因此 const 新闻稿的原始值类型表达式等同于常量。

对于对象类型(object,array,function等),表达式指向的内存地址其实是保存了一个指向实际数据的指针,所以 const 根本无法保证指针是不可修改的,至于指针指向的数据结构是无法保证其不能被修改的(在堆中)。

实例标识符:

const obj = { value: 1 } obj.value = 2 console.log(obj) // { value: 2 } obj = {} // TypeError: Assignment to constant variable

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务