变量的初始化, 重复声明
var定义的变量如果没有初始化, 那么它的初始值默认是undefined
console.log(a); var a; let b; console.log(b);
const定义的变量是一个常量, 必须初始化, 而且初始化之后不能修改绑定, 但允许修改值, 这就意味着用const声明一个对象后, 可以修改该对象的属性值
使用var关键字多次声明同一个变量是合法的, 但是使用let/const多次声明同一个变量是不合法的, let/const禁止重复声明
var a = 10; var a = 20; // 覆盖前面的变量, 不会报错 let b = 10; let b = 20; // 会抛出语法错误 var c = 10; let c = 10; // 报错
作用域和作用域链
作用域就是用于确定在何处以及如何查找变量的一套规则, 控制着变量和函数的可见性和生命周期.
作用域查找会在找到第一个匹配的标识符时停止。在多层的嵌套作用域中可以定义同名的标识符,这叫作“遮蔽效应”(内部的标识符“遮蔽”了外部的标识符)。抛开遮蔽效应,作用域查找始终从运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止。
var关键字声明的全局变量会自动成为全局对象的属性, 这意味着在全局作用域中使用var有可能会覆盖掉一个已经存在的全局属性.
var声明的变量的作用域有全局作用域和函数作用域, 没有块级作用域. let/const声明的变量增加了块级作用域
从 ES3 开始,try/catch 结构在 catch 分句中具有块作用域. 因此在es6之前的环境里可以利用catch实现块级作用域
try { throw undefined; } catch(a) { a = 2; console.log(a); } console.log(a);
提升机制
提升机制: 先声明再赋值. 函数声明和var声明都会被提升. 函数会首先被提升
a = 10; var a; // 不会报错 a = 20; let a; // 因为暂时性死区而报错 var funcs = []; for(var i = 0; i < 10; i++) { funcs.push(function() { console.log(i); }); } funcs.forEach((item) => { item(); // 打印输出10个数字10 });
什么是暂时性死区
只要块级作用域内存在let/const关键字声明的变量, JavaScript会将该变量声明移入暂时性死区中, 访问暂时性死区中的变量会触发运行时错误, 只有在执行过let/const变量声明语句之后, 该变量声明才会从暂时性死区中移除, 之后可以正常访问.
var tmp = 10; if(true) { tmp = 20; // 试图访问暂时性死区中的变量, 报错 let tmp; } function fn(x=y, y=2) { return [x, y]; } fn(); // 报错