块级作用域
ES5 中作用域有:全局作用域、函数作用域。但是没有块作用域的概念。
ES6 中新增了块级作用域。块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域。
<script type="text/javascript">
{
var a = 1;
let b = 2;
console.log(a); // 1
console.log(b; // 2
}
console.log(a); // 1
console.log(b); // 报错
// 可见,通过var定义的变量可以跨块作用域访问到。let定义的变量,外部访问就会报错
(function A() {
var b = 2;
console.log(b); // 2
})();
// console.log(b); // 报错,
// 可见,通过var定义的变量不能跨函数作用域访问到
if(true) {
var c = 3;
}
console.log(c); // 3
for(var i = 0; i < 4; i++) {
var d = 5;
};
console.log(i); // 4 (循环结束i已经是4,所以此处i为4)
console.log(d); // 5
// if语句和for语句中用var定义的变量可以在外面访问到,
// 可见,if语句和for语句属于块作用域,不属于函数作用域。
</script>
let、var、const 的区别
var 用来声明变量的,没有块的概念,可以跨块访问,但是不能跨函数访问;
let 也是用来声明变量的;声明的变量只有在let命令所在的块内才有效
const是用来声明一个常量的。即是一个只读变量,一旦声明,就必须立即初始化;
var、let 的不同点
- let所声明的变量只有在所在的代码块内才有效;var会变量提升;
let所声明的变量一定要在声明后使用,否则会报错;var可以在声明之前使用,值为undefined;
//var 的情况 console.log(foo); //输出undefined var foo=2; //let的情况 console.log(bar); //报错 ReferenceError let bar=2;ES6有明确规定,如果区域块中存在let或const命令,则这个区域块对这些命令的声明的变量从一开始就形成了封闭作用域,即只要在声明之前使用,就会报错。
var temp=123; if(true){ temp='abc'; //ReferenceError let temp; }
个人理解的封闭作用域就是暂时跟外部的作用域没有关联(在区域块中存在let或const),类似于一个独立的作用域;所以我们在if的块级作用域中使用没有声明的temp,就会报错;
- let不允许在相同的作用域内重复声明同一变量(因此,不能在函数内部重新声明参数),var没有限制。
//报错 function(){ let a=10; var a=1; }; //报错 function(){ let a=10; let a=1; }; //报错 function func(args){ let arg; }; //不报错,此时声明的变量已经跟上面的arg不在一个作用域下了 functuon fun(arg){ { let arg; } };
const
const 声明的是一个只读变量,一旦声明,常量的值就不可以改变。
const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
- 对于简单数据类型(数值、字符串、布尔值),值就是保存在变量指向的内存地址中,因此等同于常量;
- 对于复合类型的数据(主要针对对象和数组),变量指向的内存地址保存的只是一个指针。const只能保证这个指针是固定的。
const foo={};
foo.prop=123; //为foo 添加一个属性,可以成功(内存地址没有改变)
foo={}; //将foo指向另一个对象,报错(此时内存地址改变了)