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(){}
两种写法都是一样的,只是一个是函数方式,一个是函数字面量方式。当然,这只在弱类型语言行得通~

以上,便是预编译和变量提升的所有知识点啦~

上一篇下一篇

猜你喜欢

热点阅读