let
块级作用域
内层变量不可能覆盖外层变量
用来计数的循环变量不会泄露为全局变量
块级作用域的出现,立即执行函数表达式(IIFE)就不再必要了。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
// 用babel转为es5后
"use strict";
var a = [];
var _loop = function _loop(i) {
a[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
a[6](); // 6
JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。 (只在for循环有用)
let i=0;i++;
console.log(i); // 1
i=0;i++;
console.log(i); // 1
立即执行函数表达式(IIFE)
// 最常用的两种写法
(function(){ /* code */ }()); // 老道推荐写法
(function(){ /* code */ })(); // 当然这种也可以
// 括号和JS的一些操作符(如 = && || ,等)可以在函数表达式和函数声明上消除歧义
// 如下代码中,解析器已经知道一个是表达式了,于是也会把另一个默认为表达式
// 但是两者交换则会报错
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
// 也可以选择一元运算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
// 也可以这样
new function(){ /* code */ }
new function(){ /* code */ }() // 带参数
块级作用域与函数声明:
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。 ES6
引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
为了减轻因此产生的不兼容问题,ES6在附录B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
1、允许在块级作用域内声明函数
2、函数声明类似于var 会提升到全局作用域的头部
3、函数声明还会提升到块级作用域的头部
不存在变量提升
let不会像var那样会发生‘变量提升’现象即函数及变量的声明都将被提升到函数的最顶部。。所以变量一定要在声明后使用,否则报错。
不允许重复声明
let不允许在相同作用域内重复声明同一个变量
暂时性死区(TDZ)
如果区块存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。只要在声明前使用这些变量,就会报错。
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
function a() {
console.log(i);
function b(){
let i = 10;
console.log(j);
function c(){
let j = 20;
console.log(i);
console.log(j)
}
c()
}
b()
}
a() // Uncaught ReferenceError: i is not defined
//转为es5
"use strict";
function a() {
console.log(i);
function b() {
var i = 10;
console.log(j);
function c() {
var j = 20;
console.log(i);
console.log(j);
}
c();
}
b();
}
a();
function a () {
console.log(i);
let i = 10;
console.log(j);
let j = 20;
console.log(i);
console.log(j);
}
//转为es5
"use strict";
function a() {
console.log(i);
var i = 10;
console.log(j);
var j = 20;
console.log(i);
console.log(j);
}
const
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
const声明一个只读的常量,一旦声明,常量的值就不能改变,这意味着,const一旦声明常量,就必须立即初始化,不能等到之后再赋值。因此,改变常量和只声明不赋初始值都会报错。
var i = 5;
let j = 10;
const i =6; // 报错
const j = 11; // 报错
// JS是按照代码块来进行编译和执行的,每一个script就是一个块,代码块间相互独立,但变量和方法共享
<script>
const foo = 1
</script>
<script>
foo = 2
</script>
// Uncaught TypeError: Assignment to constant variable.
对于复合类型的常量,常量名不指向数据,而是指向数据所在的地址。const命令只是保证常量名指向的地址不变,并不保证该地址的数据不变,也就是说,将对象常量指向另一个地址会报错,但对象本身是可变的,可以为其添加,修改属性,因此将一个对象声明为常量必须十分小心。
const obj = {};
obj.name = “Alice”;
obj = {}; // 报错
跨模块常量
const声明的常量只能在当前代码块有效,如果想设置跨模块的常量可以采用下面的写法:
//constants.js
export const A = 1;
export const B = 1;
export const C = 1;
//test1.js
import * as constants from './constants'
//test2.js
import {A, B} from './constants'
网友评论