es6 的 let 所声明的变量,只在 let 命令所在的代码块内有效。for循环的计数器,就很适合用let命令:javascript
for (let i=0; i< 10; i++) { //.. } console.log(i) // ReferenceError: i is not defined
由于计数器 i 只在 for 循环体内有效,在循环体外引用就会报错。java
for循环有一个特别之处,设置循环变量的那部分是一个父做用域,而循环体内是一个单独的子做用域。es6
for(let i =0; i< 3; i++) { let i = 'abc'; console.log(i); } // abc // abc // abc
上面代码输出了 3 次 abc, 这代表函数内部的变量 i 和循环变量 i 不在同一个做用域,有各自独立的做用域;编程
咱们知道, var 声明的变量会存在变量提高现象,可是 let 不会,let 声明的变量必定在声明后使用。不然报错。好比:数组
// es5 console.log(i); // undefined var i = 10; // es6 console.log(j);// ReferenceError let j = 10;
只要块级做用域内存在 let 和 const 命令,它所声明的变量就“绑定”在这个区域,再也不受外部的影响。凡是在声明以前就使用这些变量,就会报错,这种称为“暂时性死区(TDZ)“;浏览器
TDZ的本质是只要进入当前做用域,所要使用的变量就已经存在了,可是不可获取,只有等到声明变量的那一行代码出现,才能够获取和使用该变量。数据结构
let i = 5; if(true) { console.log(i);// Uncaught ReferenceError: i is not defined let i=10; }
虽然全局做用域内有 i 这个变量,可是局部做用域里用 let 声明了一个同名变量,因此最后 i 就被绑定到局部做用域里,它未声明就使用,因此会报错。ide
这样的设计是为了让你们养成良好的编程习惯,变量必定要在声明以后使用。不然就报错。函数
let不容许在相同做用域内,重复声明同一个变量;es5
function fuc() { let a= 10; let a = 1; }// 报错 function func () { let a= 10; { let a = 1; } }// 不报错,不属于同一做用域
es5 只有全局做用域和函数做用域,没有块级做用域,这产生不少不合理的场景。
场景1,内层变量可能会覆盖外层变量
var tmp = new Date(); function f() { console.log(tmp); if(false) { var tmp = 'hello world' } } f()// undefined;
if 代码块的外部使用外层的 tmp 变量,内部使用内层的 tmp 变量,可是。函数 f 执行后,输出为undefined;缘由在于变量提高致使的 tmp 变量覆盖了外层的 tmp 变量;
场景2, 用来计数的循环变量泄露为全局变量
var s = 'hello'; for(var i = 0; i < s.length; i++) { console.log(i); } conole.log(i);
这里,i 只是用来控制循环, 可是它没有消失,泄露成了全局变量。
函数能不能在块级做用域中声明?
es5 规定,函数只能在顶层做用域和函数做用域之中声明,不能在块级做用域中声明。
function f() { console.log('outside');} (function () { if(false) { // 重复声明一次函数 function () { console.log('inside');} } f(); }());
这串代码在 es5 中运行,照规定来讲是非法的,可是为了兼容,仍是支持在块级做用域中声明函数,所以会获得’inside'; 由于在 if 中声明的函数会被提高到函数头部,实际执行的代码为:
function f() { console.log('outside');} (function () { function f() {console.log('inside');} if (false) { } f(); }());
在 es6中 执行会怎么样?会报错。
es6规定,函数能够在块级做用域内声明。函数声明的语句相似于let,在块级做用域以外不能够引用。
上面的代码在符合es6的浏览器中,实际运行的是:
function f() { console.log('outside');} (function () { var f = undefined; if (false) { function f() {console.log('inside');} } f(); }());
因此咱们应该避免在块级做用域内声明函数,若是须要,函数声明应该写成函数表达式,如
{ let a='haha'; let f = function () { return a; } }
块级做用域不会返回值,咱们能够将块级做用域变为表达式。在 {} 以前加上do, 而后就会返回内部最后执行的表达式的值。不过如今这只是个提案,如今这样写 do是浏览器没法解析的。
let x = do { let t = f(); t*t+1; }
const定义的是常量,它不是指变量的值不能改动,而是变量指向的那个内存地址不能改动。对于简单类型的数据,值就保存在变量指向的那个内存地址,所以等同于常量,而符合类型的数据(数组和对象),变量指向的内存地址,保存的只是一个指针, const只能保证这个指针式固定的,而它指向的数据结构是不可控的。
let 和 const 的特性有: