1.let命令
1-1. ++牢记重点++
let声明变量只在所在块级作用域起作用即{}
不存在变量提升即无声明提前
在let声明某个变量的前面,都属于这个变量的死区
let声明块状区域内不允许重复声明
1-2.++重点案列解释++
(1).{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
- es5 没有块级作用域所以var声明不报错而es6{}为块级作用域外面不能访问里面
(2).for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
- for循环的计数器,就很合适使用let命令。计数器i只在for循环体内有效,在循环体外引用就会报错
(3).var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a6; // 10
- 最终输出10因为i是全局变量 要等for循环全部执行完毕在执行函数a6而i的最终值为10
(4)var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a6; // 6
- 变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
(5).for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
- for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
(6).// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
- 不存在变量提升
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
- let前面都是死区
typeof x; // ReferenceError
let x;
typeof undeclared_variable // "undefined"
- tyoeof 检验不安全会报错
// 报错
function () {
let a = 10;
var a = 1;
}
// 报错
function () {
let a = 10;
let a = 1;
}
function func(arg) {
let arg; // 报错
}
function func(arg) {
{
let arg; // 不报错
}
}
- 不允许重复声明
2.块级作用域
++2-1.为什么需要块级作用域?++
- 内层变量可能会覆盖外层变量
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefinedvar tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
- 用来计数的循环变量泄露为全局变量
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
++2-2.es5模仿块级作用域++
(function () {
var tmp = ...;
...
}());
++2-3. es6块级作用域++
{
let tmp = ...;
...
}
++2-4.块级作用域的弊端---无法取到里面的值++
{
let t = f();
t = t * t + 1;
}
- 块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量
let x = do {
let t = f();
t * t + 1;
};
- 使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式变量x会得到整个块级作用域的返回值
3.const命令
++const声明一个只读的常量。一旦声明,常量的值就不能改变。++
(1)const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
- const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值
- 只声明不赋值,就会报错
- const的作用域与let命令相同:只在声明所在的块级作用域内有效。
- const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
(2)var message = "Hello!";
let age = 25;
// 以下两行都会报错
const message = "Goodbye!";
const age = 30;
- const声明的常量,也与let一样不可重复声明。
4.global对象
- 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
- 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
- Node 里面,顶层对象是global,但其他环境都不支持。