3

ES2015已经定稿一年多了,想必大家早就用上letconst来充分利用块作用域的优势了吧?那么,你们知道块作用域都是怎么声明的吗?

在各种教程资料的例子里,块作用域都是出现在for(……){……}/if(……){……}/while(……){……}这些语句里的,那你有没有想过,块作用域其实跟这些逻辑控制语句完全没有关系?

前置知识

本文需要有块作用域以及let / const相关知识,如有欠缺,请看这里

块作用域的标识

块作用域的标识其实是那一对大括号{},换句话说,我们不需要任何逻辑控制语句就可以直接使用大括号来创建块作用域:

var a = 2;
{
  let a = 3;
}
console.log(a); // 输出2

块作用域的隐式声明

相信大家一般都不会直接用大括号来创建块作用域,而是像下面这个例子来使用:

var a = 2;
var b = 2;
var c = 0;
if (a === b) {
  let c = 2;
  a ++;
  b -= c;
}
console.log(a); // 3
console.log(b); // 0

你可能注意到,这段代码里定义了两个变量c,这有时并不是故意重复起名为c,而是前面一大堆代码,根本不知道变量名c已经被用掉了。尽管如此,由于块作用域的缘故,这段代码还是能够安全地运行。

但如果这段代码由别人接手,而他又急于改需求呢,那很可能就会出现以下这种情况:

var a = 2;
var b = 2;
var c = 0;
if (a === b) {
  let c = 2;
  a ++;
}
b -= c;
console.log(a); // 3
console.log(b); // 2

需求是这样改的:不需要判断a === b就执行b -= c;了。此时,这段代码在运行时也不会报错(因为前面早已定义有了一个同名变量c),但结果却出错了,而且往往这种错误还不容易发现。

块作用域的显式声明

如何避免上述问题呢?答案是:利用额外的一对大括号来做块作用域的显式声明

我们试着用块作用域的显式声明来修改上述代码:

var a = 2;
var b = 2;
var c = 0;
if (a === b) {
  { // 使用大括号来包裹住块作用域变量相关的代码块
    let c = 2;
    b -= c;
  }
  a ++; // 操作的都是块作用域外部就定义好的变量,剔除在大括号以外
}
console.log(a); // 3
console.log(b); // 0

看着有点别扭是吧?没关系,我们看看按需求修改后的代码:

var a = 2;
var b = 2;
var c = 0;
if (a === b) {
  a ++;
}

{
  let c = 2;
  b -= c;
}

console.log(a); // 3
console.log(b); // 0

duang!

爸爸妈妈再也不用担心我重构代码的时候出一大堆bug了!

总结

块作用域的显式声明实际上是主动分隔开接受块作用域管理的let / const变量和不接受块作用域管理的var变量,从而帮助我们在重构代码时,能更轻松、更放心地挪动代码。

本文首发于Array_Huang的技术博客——实用至上,非经作者同意,请勿转载。
原文地址:https://segmentfault.com/a/1190000007639527

array_huang
10.4k 声望6.6k 粉丝