ES6 变量声明

let与var
  • let 声明具有块级作用域 (如果没有块: 用于计数的循环变量泄露为全局变量)

对于一段代码

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

用 var 声明的变量是全局的 这里的i 就是一个,就是全局的i,每次循环 i的值都会发生变化,赋给数组的函数内部的console.log(i) 指的就是外部的i

理解: 数组元素的[i] 与console.log(i)的i 不同,元素这里是立即会获取 增长的i 但是 console.log(i) 只是一个声明,在执行的时候,再去拿i 的值,它拿到的i 的值,是最后增长结束的 i的值,下面这样会有不同

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

立即执行的话,会不同 就是输出理想的 1-9

如果使用 let

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

这里 i 就是在本轮循环中有效,每次循环的i 都是一个新的变量

JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算

for循环还有一个特别之处,

就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域

1
2
3
4
5
6
7
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
let
  • let 声明 不存在变量提升

var 声明变量,会发生提升,变量可以在声明之前使用 值 为 undefined

  • 声明之前是不能使用的(临时性死区)
  • 不允许重复声明

不能在函数内部重新声明参数

1
2
3
4
5
6
7
8
9
function func(arg) {
let arg; // 报错
}

function func(arg) {
{
let arg; // 不报错
}
}

没有块级作用域 易造成 用于计数的循环变量泄露为全局变量

1
2
3
4
5
6
7
var s = 'hello';

for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}

console.log(i); // 5

上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

const 声明一个只读的常量

本质:

并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动.

对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了

1
2
3
4
5
6
7
8
const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

理解一下:

foo 指向的是一个内存地址这个地址指向了一个数组或者对象,使用const 声明后,这个地址就只能一直指向这一个 数组或者对象,不能指向其他

常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

1
2
3
4
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错

常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错

如果需要冻结一个对象

1
2
3
4
const foo = Object.freeze({});
// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

ES6 中声明变量

从 ES6 开始 全局变量将逐步与顶层对象的属性脱钩。let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

顶层对象不统一

  • 浏览器顶层是 window,Node 和web worker 没有window
  • 浏览器和 web worker self 指向顶层,但Node没有self
  • Node 顶层是 global,其他环境都不支持。