ES6之块级作用域

0x01 es6 之前的作用域

  • 全局作用域
  • 函数作用域

由于上面的两种作用域,在 JavaScript 中存在一个术语:变量提升(hoisting),如下:

1
2
3
4
5
function func(){
console.log(test);
var test = 1;
};
func();

执行的结果并不是”test is not defined” ,而是 undefined.

这是因为在执行 func() 时,使用 var 定义的 test被提升到函数顶部进行定义(var test),与下面的代码的结果相同:

1
2
3
4
5
6
7

function func(){
var test;
console.log(test);
test = 1;
};
func();

0x02 es6 的块级作用域

由于let和const属于ES6,所以都必须使用严格模式,否则会报错

1
'use strict'

let

let 与 var 类似,都是用来声明变量的,但是与 var 相比,let 存在以下特点:

  • 1.let 所定义的变量,只在块级作用域内部有效

  • 2.let没有‘变量提升’的特性,而是‘暂时性死区(temporal dead zone)’特性

let 在块级作用域内生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'use strict';
function func(args){
if(true){
//let声明i
let i = 6;
//在if内打印i值
console.log('inside: ' + i);
}
//在if外,再次打印i值
console.log('outside: ' + i);
};
func();

// inside: 6
// error: Uncaught ReferenceError: i is not defined

可以看到,在 if 外无法访问到 i 的值.

如果用 var 定义,在 if 外层也可以访问到:

img

暂时性死区

1
2
3
4
5
6
7
8
9
10
'use strict';
function func(){
//在let声明前,打印i
console.log(i);
let i;
};
func();


//i is not defined

换成使用 var 定义 i:

img

在let声明变量前,使用该变量,它是会报错的,而不是像var那样会‘变量提升’。

其实说let没有‘变量提升’的特性,不太对。或者说它提升了,但是ES6规定了在let声明变量前不能使用该变量。

如下:

1
2
3
4
5
6
7
8
9
10
11
'use strict';
var test = 1;
function func(){
//打印test的值
console.log(test);
let test = 2;
};
func();


//error: Uncaught ReferenceError: Cannot access 'test' before initialization

如果let声明的变量没有变量提升,应该打印’1’(func函数外的test);而他却报错,说明它是提升了的,只是规定了不能在其声明之前使用而已。我们称这特性叫“暂时性死区(temporal dead zone)”。且这一特性,仅对遵循‘块级作用域’的命令有效(let、const)。

1
2
3
4
5
6
7
8
9
10
11
12
13


'use strict';
var test = 1;
function func(){
//打印test的值
console.log(test);
// let test = 2;
};
func();


// 1
1
2
3
4
5
6
7
8
9
10
11
12
13


'use strict';
var test = 1;
function func(){
//打印test的值
console.log(test);
var test = 2;
};
func();


// undefined

一个经典案例:

1
2
3
4
5
6
7
8
9
10
var arr = [];
for(var i = 0; i < 2; i++){
arr[i] = function(){
console.log(i);
};
};
arr[1]();


// 2

arr[1]()会输出2,原因是var声明的变量会变量提升,且当执行arr[1]函数时,i取自于父函数的i,而此时i已经变为2了,所以就会打印2咯。

1
2
3
4
5
6
7
8
9
10
11
12
13

//使用闭包


var arr = [];
for(var i = 0; i < 2; i++){
arr[i] = (function(i){
return function(){
console.log(i);
};
}(i));
};
arr[1]();
1
2
3
4
5
6
7
8
9
10
11
12
13

// 使用 let

'use strict';
var arr = [];
for(let i = 0; i < 2; i++){
arr[i] = function(){
console.log(i);
};
};
arr[1]();

// 1

const

const命令与let命令一样,声明的变量,其作用域都是块级。

所以const遵循的规则与let相差无二,只是,const是用来声明恒定变量的。

且,用const声明恒定变量,声明的同时就必须赋值,否则会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

'use strict';
function func(){
const PI;
PI = 3.14;
console.log(PI);
};
func();



// error: unknown: Unexpected token (3:12)

// 1 | 'use strict';
// 2 | function func(){
// > 3 | const PI;
// | ^
// 4 | PI = 3.14;
// 5 | console.log(PI);
// 6 | };

const 正确的使用方式为声明的同时并赋值:

1
2
3


const pi = 3.1415926
thank u !