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)