JavaScript预编译与变量提升
2019-05-30 本文已影响0人
LeeYaMaster
去年,啃了很久很久的大犀牛(JS权威教程),啃得牙齿疼,今天重新回顾大犀牛,发现挺简单的,之前一直觉得难懂的变量提升,现在一眼就会了,于是便写下这篇博客,就当重新回顾一下了。
JavaScript是一门解释型的语言 , 想要运行JavaScript代码需要两个阶段
编译阶段: 编译阶段就是我们常说的JavaScript预解释(预处理)阶段,在这个阶段JavaScript解释器将完成把JavaScript脚本代码转换到字节码
执行阶段: 在编译阶段JavaScript解释器借助执行环境把字节码生成机械码,并从上到下按顺序执行
栈内存:用来提供一个供JS代码执行的环境,即作用域(全局作用域/私有的作用域)
堆内存:用来存储引用数据类型的值。对象存储的是属性名和属性值,函数存储的是代码字符串。
什么是预编译?
预解释:JavaScript代码执行之前,浏览器首先会默认的把所有带var和function的进行提前的声明或者定义
1、变量的声明提前
console.log(a);//undefined
var a = 1;
会编译成
var a;
console.log(a);
a = 1;
2、function的声明提前
var =>在预解释的时候只是提前的声明
function =>在预解释的时候提前的声明+定义都完成了
for循环,也是函数作用域,if,switch不是。
3、只会提前window作用域的变量,在函数里面的,只会调用的时候,再声明提前。
实战篇
第一弹:
var a=1,b=2,c=3;
function main(a){
a = 4;
var b = 5;
c = 6;
}
main(6);
console.log(a);console.log(b);console.log(c);//1,2,6
a输出为6,是因为a是作为参数传进去,传到函数体,那么便是私有变量。
b输出为2,是因为在函数里var b,重新定义,由于在函数体内,所以也是私有变量。
c输出为6,是因为在函数里,他会去查找c,如果没有,往上一级一直查找,所以,会更改全局变量,输出为6
第二弹:
var num = 0;
function main(num1,num2){
console.log(num);//undefined
var num = num1+ num2;
console.log(num);//30
}
main(10,20);
console.log(num);//0
第一个为undefined是因为变量提升,var num;所以为undefined
第二个输出30,是因为参数进去了,所以为30
第三个为0,是因为在方法里,用了var,重新定义了一个局部变量,只是名字和全局变量一样而已,所以输出的时候,还是全局变量,所以为0
第三弹:
if(!"num" in window){
var num = 12;
}
console.log(num);//undefined
原因在于变量提升,if不是函数作用域,所以var num会提升到最上面,所以也就成了全局作用域了。
函数是一等公民:
第四弹:
function a(){}
var a;
console.log(typeof a);
a();
输出function,原因是因为函数会首先被提升
第五弹:
fn()
var fn = function a(){
console.log("ok");
}
报错,fn is not a function,是因为函数提升,var fn = xxx ; "="后面的不会提升,只会提升前面部分。
第六弹:
var a = 1;
function a(a){
console.log(a);
var a = 3;
}
a(2);
报错,a is not a function。是因为函数声明,比变量声明优先级更高,并且把变量覆盖,但是变量可以重新定义,var a = 3;又把函数覆盖了。所以会输出不是一个函数。
为了便于理解,函数会编译为:
function a(a){
console.log(a);
var a = 3;
}
a = 1;
a(2)
第七弹:
function a(){return true};
console.log(a);
console.log(a());
第一个会输出整个函数字符串,第二个则会调用整个函数。这就是区别啦~
function a(){}
var a = function(){}
两种写法都是一样的,只是一个是函数方式,一个是函数字面量方式。当然,这只在弱类型语言行得通~
以上,便是预编译和变量提升的所有知识点啦~