1.let与const定义变量
1.var 和 function
var function 存在变量提升
var 只会提前声明,function既声明又定义
在全局作用域下,使用var和function声明的变量会给window增加属性
console.log(a);//hello
console.log(getA);//打印出函数
var a = 1;
function getA() {}
var a = 2;
console.log(a);
console.log("getA" in window);
2.let
console.log(a)//报错:a is not undined
let没有变量提升,因此使用console打印,并不会提示undefined,而是直接报错
- 使用let没有变量提升
- 不可以重复声明
- 不会给window增加属性
let a = 1;
//let a = 2;//报错:'a' has already been declared
console.log(window.a);
4.var在同一个作用域下可以多次声明同一个变量,let不可以
function b(){
let a = 3;
let a = 4;
}
b();
//Identifier 'a' has already been declared
5.如果用let声明过了 就不要再用var了
function b(){
let a = 3;
var a=4;
}
b();
//报错:变量被重复声明,如果用let声明过了 就不要再用var了
3.const
- 没有变量提升
- 不可以重复声明
- 不会给window增加属性
- const定义变量,一旦声明必须赋值
- const定义的是一个常量,不可以重新赋值
- 通过const声明的变量不能被修改,不能修改引用空间,但是可以修改内容,不能修改变量的地址
const a = {name:'zfpx'};
a.age = 9;
console.log(a);
//{name: "zfpx", age: 9}
let a;
console.log(a);//undefined
//const b;//报错:Missing initializer in const declaration
const b = 2;
//b = 3;//报错:Assignment to constant variable.
- 在使用var时,可以将已经声明的变量再次声明,而在let声明后,再次声明是不允许的
- 不会给window增加属性,使用 in 来检测window的属性,是检测不到的,甚至,window对象都被允许打印出来
- const在ES6中
- 同let类似:没有变量提升,不可以重复声明,不会给window增加属性
- 同时,const定义的是常量,var和let声明变量后,可以不赋值,但是const必须声明的时候就定义
- var和let在声明和定以后,可以赋新值,但是const不允许再赋值。因为它是一个常量
4.块级作用域
- { }:一个{ }就是一个块级作用域
- 块级作用域下var和function声明的变量依然是全局的
- 块级作用域下let和const声明的变量是私有的,在外面是获取不到的
- { }如果想表示一个对象,不可以放在行首
{
var a = 0;
function getA() {
console.log("ok");
}
let b = 1;
}
console.log(a);//能够成功打印
getA();//成功执行
//console.log(b);//报错:b is not defined
1.for循环,if判断,创建对象的时候都会产生{}
{name:"Cyan",age:19}//这样写会报错,当做块级作用域
2.要表示一个对象千万不要放在行首
let obj = {name:"Cyan",age:19};
({name:"Aqing",age:20})//这两种方式都可以
3.eval
console.log(eval('{name:"Aqing",age:20}'));//报错
这样会报错,因为eval会直接把字符串转换成一个{},所以我们拿括号包起来
console.log(eval('({name:"Cyan",age:20})'));
eval('var o = {name:"Aqing",age:20}');
console.log(o);
4.if(){} 中的function 只会提前声明,不会定义,当if判断条件成立的时候,先给函数赋值,代码再执行
if(1){
var A = 1;
function getAA() {
}
}
console.log(A);
console.log(getAA);
5.for循环
1.var 不支持封闭作用域,会声明到全局作用域上
1.函数作用域
2.全局作用域
function () {
for (var i = 0; i < 3; i++) {
console.log(i);
}
};
console.log(i); //在外界拿到i
console.log(window.i);//全局下的i
//0 1 2 3 3
2.使用闭包,自执行函数
(function () {
for (var i = 0; i < 3; i++) {
console.log(i);
}
})();
console.log(i); // i拿不到
console.log(window.i);
//0 1 2
i拿不到了,被封闭在函数内。
3.异步代码
for(var i = 0; i<3;i++){
function (i) {
setTimeout(function () {
console.log(i);
}, 1000);
};
}
需求:,每一秒打印出i
代码执行栈先执行同步代码,把异步代码压到队列里,等待同步代码执行完,开始清空队列
此时打印的时候:3 3 3
1.闭包解决:
for(var i = 0; i<3;i++){
(function (i) {
setTimeout(function () {
console.log(i);
}, 1000);
})(i);
}
// 0 1 2
每次的i都找自己的i
2.let解决:
let和{}配和可以产生一个作用域
let支持块级作用域声明的变量只会声明在当前作用域内
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
console.log(i);
使用var声明的for循环中的循环值,在循环外是可以访问到的,也就是说,这个值是全局的。同时,这个值在外面访问时,是已经步长累加完的值。
使用let声明的for循环中的循环值,因为是属于块级作用域私有的,所以循环体外是访问不到的。
7.预解释问题 变量提升 用let解决这个问题
let a = 1;
{
console.log(a);
let a = 2;
}
6.暂存死区,
如果作用域内 有这样一个变量 那么这个作用域内就会绑定这个变量,不会继续向上查找了
let a = 1;
{
let a = 2;
console.log(a);
}