var、function、let、const 的区别及变量提升
JS的解析器会做两部分的工作: 1)预解析 | 预解析仓库 = “找东西“(找VAR , FUNCTION 以及参数) 2)逐行解读代码
预解析时,var 、function 会发生我们通常所说的变量提升
// 变量提升 var function console.log(a) // a() { // console.log(this is a2) // } var b=3 a() console.log(a) var a = 1 function a() { console.log(this is a1) } console.log(a)// 1 function a(a, b) { console.log(this is a2) console.log(a) console.log(b) } console.log(a)// 1 var a = 2 console.log(a)// 2 log: /** ƒ a(a, b) { console.log(this is a2) console.log(a) console.log(b) } this is a2 undefined undefined ƒ a(a, b) { console.log(this is a2) console.log(a) console.log(b) } 1 1 2 {a: 3} */ /** * 预解析步骤: * 1.首先解析到第七行var a, 在预解析器中定义 a =undefined * 2.解析到a1, 将解析器中 a = a() { console.log(this is a1) } 3.解析到a2, 将解析器中 a = a() { console.log(this is a2) } 4.解析到var a= 2,由于a =undefined, 所以a = a() { console.log(this is a2) } */
预解析步骤:
1.首先解析到第七行var a, 在预解析器中定义 a =undefined
2.解析到a1, 将解析器中 a = a() {
console.log(this is a1)
}
3.解析到a2, 将解析器中 a = a() {
console.log(this is a2)
}
4.解析到var a= 2,由于a =undefined, 所以a = a() {
console.log(this is a2)
}
// 一是不存在变量提升:
// 二是let声明的变量不能重复声明,否则会报错
// var i = 1;
// var i = 2;
// console.log(i)//2
// let i = 1;
// let i = 2;
// console.log(i)//报错
// 三是新增了块级作用域。
for(var i = 0; i < 5; i++){
}
console.log(i) // 5
for(let i = 0; i < 5; i++){ // 这个i只能在这个for循环内使用
}
console.log(i) // 报错:i is not defined
// 一个常见的闭包问题就可以用let来解决。
// for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
for (let i = 0; i < 3; i++) {
let i = abc;
console.log(i);
}
// abc
// abc
// abc
// 上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
for(var i = 0; i < 5; i++){
setTimeout(function(){
console.log(i)
}, 1000)
}
// 这个可谓是经典的闭包题了,结果是一次性输出5个5。如何让它输出01234呢,ES5我们用IIFE来解决。
for(var i = 0; i < 5; i++){
(function(e){
setTimeout(function(){
console.log(e)
}, 1000)
})(i)
}
// 将代码放在一个IIFE中创建了一个独立的作用域,传入i,这样就实现了对i的暂存。(详细可参看我的另一篇关于闭包的文章。)
// ES6就可以用let来解决了。
for(let i = 0; i < 5; i++){
setTimeout(function(){
console.log(i)
}, 1000)
}
// 其实JS引擎解析上述代码中的let,就是按照ES5的规范来解析的。即创建一个IIFE传入i.
// console.log(b)
// let b = 2
// for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
for (let i = 0; i < 3; i++) {
let i = abc;
console.log(i);
}
// abc
// abc
// abc
// 上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
const c = {}
c.a=3
console.log(c)