预解析之变量提升
提升的对象包括:
- 函数声明
- 变量声明
- 函数内部作用域默认形参声明
1.函数声明和变量声明是同一个变量名
当函数声明和变量声明冲突的时候,变量声明无法覆盖函数声明,变量赋值可以覆盖函数声明 所以最后结果为10
具体代码:
a(a) //调用函数
a = 10; //变量
var a; //全局变量
//或者 var a = 10; 同上面两句
function a(a) {
//函数
}
console.log(a)//10
看到这个有的人会一脸懵逼,为什么函数a还没有声明就可以调用,a还没声明就可以赋值,这全是因为浏览器对js代码的预解析,这是代码执行之前的操作,也叫变量提升。
函数和定义变量会被提升到当前作用域最顶端,当函数名和定义变量名字一样时,函数名会覆盖变量定义。
预解析完成后的代码:
//上面预解析完成后是
function a(a) {
}
a(a) //调用函数
a = 10; //给变量a重新赋值覆盖函数体
console.log(a)//10
2.函数形参和变量声明是同一个变量名
a(a) //调用函数
a = 10; //变量
b=20;//变量
var a; //全局变量
function a(a) {
//函数
var a = 100;
b=200
console.log(a,b)
}
var b;
console.log(a)//10
当函数调用的时候,就要进入函数的局部作用域 浏览器还要重新再局部作用域中进行预解析,变量名定义提前 赋值不会提前。
- 参数的传递和函数中变量名冲突,函数形参的值会覆盖预解析的效果
- 在函数执行之前进行预解析,这时候参数还没传递
- 预解析以后 函数内代码开始执行 传参
- 在函数中如果没有定义这个变量 就要在全局作用域中查找
- 赋值的时候函数中没有这个变量根据作用域链也会将全局这个变量的值发生改变
函数体内正常预解析代码,没有形参参与:
var b;
function a(a) {
//函数
var a;
a = 100;
b = 200
console.log(a, b)
}
a(a) //调用函数
a = 10; //变量
b = 20;//变量
console.log(a)//10
函数开始执行,形参接受到实参的时候:
var b;
function a(a) {
//函数
var a =a; //定义a为形参a
a = 100;
b = 200
console.log(a, b) //100 200
}
a(a) //调用函数
a = 10; //变量
b = 20;//变量
console.log(a)//10
console,log(b)//20
在执行函数的时候,函数内部有用到b,并且被重新赋值,b由undefined变成200,改变全局变量的值,在后面的同步代码中b又被重新赋值,所以最终打印b的值为20。
JS对什么进行预解析?
- 函数传参的变量
- var 后面的变量
- .函数
都会提升到当前作用域最顶端,同名下,函数声明可以覆盖变量声明,函数体内局部预解析形参声明可以覆盖变量声明,赋值可以改变变量的值。
JS会给这些 变量、函数 赋予什么初始值呢?
- 传参,直接赋值参数;
- var 的,都会赋予一个 undefined 作为初始值;
- 函数,直接赋予 函数本身 作为初始值;(所以这就是为什么我们可以把 函数调用 放到 函数声明 之前的原因)