ES6块级作用域

517 阅读3分钟

var声明作用域

使用var操作符定义的变量会成为包含他的函数的局部变量

使用var在一个函数内部定义一个变量没就意味着该变量将在函数退出时被销毁

 function test() {
   var message = 'hi';   //局部变量
 }
 test();
 console.log("message: " + message);  // 出错

这里message变量是在函数内部使用var定义的,函数名为test(),调用他会创建这个变量,并给他赋值。

调用之后变量随即被销毁,所以在函数外打印message会导致错误

image-20210731215131286

但在函数内定义变量时省略var,可以创建一个全局变量

 function test() {
   message = 'hi';   //全局变量
 }
 test();
 console.log("message: " + message);  // message: hi

去掉之前的var操作符之后,message变成了全局变量,只要调用一次函数test(),就会定义这个变量,并且可以在函数外部访问到

image-20210731215806518

注意:虽然可以通过省略var操作符定义全局变量,但不推荐。

  • 在局部作用域中定义的全局变量很难维护
  • 在严格模式下,会导致抛出ReferenceError

let声明作用域

let声明的范围是块作用域,var声明的范围是函数作用域

 if (true) {
   var name = 'abc';
   console.log("name: " + name);  // hi
 }
 console.log("name: " + name);    // hi
 ​
 if (true) {
   let age = 22;
   console.log("age: " + age);  // 22
 }
 console.log("age: " + age);    // ReferenceError:age没有定义

age变量之所以不能在if块外部被引用,是因为他的作用与仅限于该块内部

块作用域是函数作用域的子集,因此适用于var的作用域显示同样也适用于let

image-20210731220704625

js会记录用于变量声明的标识符及其所在的块级作用域,因此嵌套使用相同的标识符不会报错,是因为在同一个块中没用重复声明

 var name = 'abc';
 console.log("name: " + name);  // name: abc
 if (true) {
   var name = 'eee';
   console.log("name: " + name);  // name: eee
 }
 console.log("name: " + name);    // name: eee
 ​
 let age = 22;
 console.log("age: " + age);  // age: 22
 if (true) {
   let age = 33;
   console.log("age: " + age);  // age: 33
 }
 console.log("age: " + age);    // age: 22

image-20210731221537937

暂时性死区

let与var另一个重要的区别就是let声明的变量不会在作用域中被提升

 // name会被提升
 console.log("name: " + name);  // name: undefined
 var name = 'abc';
 ​
 // age不会被提升
 console.log("age: " + age);  // ReferenceError:age没有定义
 let age = 22;

在解析代码时,js会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量

let声明之前的执行瞬间被称为:暂时性死区,在此阶段引用任何后面才声明的变量都会抛出ReferenceError

image-20210731222246275

全局声明

let在全局作用域中声明的变量不会成为window对象的属性,但var会成为window对象的属性

 var name = 'abc';
 console.log(window.name)  // abc
 ​
 let age = 22;
 console.log(window.age)  // undefined

image-20210731222802081

const声明作用域

const与let基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且修改const声明的变量会导致运行时错误

 const age = 22;
 age = 33;

image-20210731223438751

const声明也是块

 const age = 22;
 console.log("age: " + age);  // age: 22
 if (true) {
   const age = 33;
   console.log("age: " + age);  // age: 33
 }
 console.log("age: " + age);    // age: 22

image-20210731223611033

const声明的限制只适用于它指向的变量的引用,如果const变量引用的是一个对象,就可以修改这个对象内部的属性

 const person = {};
 person.name = 'abc';
 console.log(person.name)

image-20210731223727243

总结

  1. 不使用var
  2. const优先,let次之

let和const有助于提升代码质量,因为变量有了明确的作用域、声明位置、以及不变的值

使用const声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作

所以应该优先使用const来声明变量,只在提前知道未来会有修改时在使用let

这样可以迅速发现因为意外赋值导致的非预期行为

\