在ES6之前,JavaScript没有块级作用域,只有全局作用域和函数作用域。
变量提升即将变量声明提升到它所在作用域的最开始的部分。
1、console.log(a); / /Uncaught ReferenceError: a1 is not defined ,变量a未定义
2、console.log(a); var a = "1";console.log(a);前后分别打印了undefined 和1
之所以会是以上的打印结果,是由于js的变量提升,实际上上面的2中的代码是按照以下来执行的:
var a; //变量提升,全局作用域范围内,此时只是声明,并没有赋值
console.log(a);//undefined
a = "1";
console.log(a);//1
let是一种新的变量申明方式,它允许你把变量作用域控制在块级里面。我们用大括号定义代码块。
{
let a = 1;
}
console.log(a); / /Uncaught ReferenceError: a1 is not defined ,变量a未定义
在此可见,let 声明变量,变量不会被提升。
再看一下我们经常遇到的问题,就是for循环中用到var声明的变量
var arr = [];
for(var i=0; i<3; i++){
arr.push(function(){
console.log(i);
})
}
arr[0]() // 3
arr[1]() // 3
arr[2]() // 3
有些场景下,我们希望拿到每次遍历的索引,在es5中面对这种场景我们就需要利用到js的闭包
var arr = [];
for(var i=0; i<3; i++){
arr.push((function(a){
return function(){
console.log(a);
}
})(i))
}
arr[0]() // 0
arr[1]() // 1
arr[2]() // 2
利用let来声明变量就会变得很简单
var arr = [];
for(let i=0; i<3; i++){
arr.push(function(){
console.log(i)
})
}
const声明一个只读的常量,一旦声明,常量的值就不能改变。其实这种变量方式与java的final修饰词有点类似
const PI = 3.1415;
PI = 3;//Uncaught TypeError: Assignment to constant variable
由此可见const申明的变量不能改变值,既然不能改变值,那么必须在申明的时候需要进行初始化。
const a; //Uncaught SyntaxError: Missing initializer in const declaration
注意下面两个例子:
1、简单数据类型
var a = "1";
const b = a;
console.log(b);//1
a = "2";
console.log(b);//1
2、复合数据类型
var obj1 = {"name":"cys"};
const obj2 = obj1;
console.log(obj2); // {name: "cys"}
obj1.name="";
console.log(obj2); // {name: ""}
所以在第2个例子中,发现obj2的对象的值变了,这一点与java的final修饰符基本一致,
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
另外const的作用域与let命令相同:只在声明所在的块级作用域内有效。
const命令声明的常量也不会将其声明提升,只能在声明的位置后面使用。
最后看下下面这个例子,非常有趣
var str = "hello";
function d() {
console.log(str);
if (false) {
var str = 'world';
}
}
d();//undefined
这个例子与上面for循环的问题都是一样,就是因为es5中的var 声明的变量由于申明的提升以及作用域的问题造成了与我们预期不同的结果。
网友评论