JavaScript 代码预解析/变量和函数的声明

3/8/2017来源:ASP.NET技巧人气:2109

1. 代码预解析

所谓预解析,指的是在执行之前对代码的分析,检查看是否有错误,然后对变量进行提升。 因此在预解析的时候,js 引擎做了两件事,① 检查语法是否有问题;② 提升声明 预解析的过程: ① 当浏览器打开后,会读取 html 等文件,同时读取 js 的代码,以字符串的形式进行读取; ② 在浏览器内部有一个被称为 js 引擎的东西(v8 引擎),它会读取该字符串,并将其解析成可以执行的代码(javaScript 引擎 就是将 js 形式的字符串转换为可以使用的代码,可以执行的代码的应用程序); ③ 在解析的过程中,首先会将代码通篇读取一遍,这就是预解析。 在预解析过程中检查错误,出现错误就会报错(注意不是异常),同时会将所有的声明记录下来; ④ 在预解析没有问题的时候,才会从头开始一步一步的解释执行代码。

2. 什么是声明

声明的含义原本是,告知以让大家都知道有什么存在。 在 js 中的声明是指:① 变量 ② 函数 变量的声明是让计算机在使用某变量的时候,知道用什么东西; 函数的声明是让计算机在调用函数的时候,知道执行什么代码。
console.log(num);//报错,num is not defined,此错误在执行时出现,而非预解析时出现





如何声明?

(1)声明变量
var num;


注意:

① 重复声明无效

② 如果变量赋值,没有使用 var,那么会称为全局变量(注意:严格模式中报错)
"use strict"; //严格模式


③ 连续声明多个变量时一定要注意符号
var num1, num2, num3, num4;
//不要少了符号
var num1 = 1,num1 = 1,num1 = 1,num1 = 1;




(2)函数声明
function 函数名() {
    // 函数声明
}同时需要注意:函数声明必须独立于语句,成为一个单独的代码结构,只允许出现在全局范围内函数中的全局范围内


if(1){
    function f() {
        //不是声明
    }
}
function foo(){
    function f() {
        //在函数内声明
    }
}


3. 什么是记录声明

(1)代码片段1
foo();
function foo() {
    console.log('ok');
}


代码在执行之前会先预解析,检查到有函数声明,因此在执行代码之前,js 引擎就知道有函数 foo 了,因此在执行代码时调用 foo 就不会报错。




(2)代码片段2
foo();//foo is not defined
+function foo() {
    console.log('ok');
}


函数不是一个独立的存在,是一个和 + 连接的表达式,因此在预解析的时候没有检查到声明,因此浏览器不会记录函数,在第一次调用的时候就会出现错误。




(3)代码片段3
foo();//foo is not a function
var foo = function () {
    console.log('ok');
};


在代码执行之前,预解析检查到有 foo 声明(变量),因此记录变量 foo

在代码执行的第一句调用函数(此时还未赋值),报错,foo不是一个函数




(4)在预解析的时候,记录声明由两部分构成

① 如果是变量声明,那么就记录下变量名,并且将其值确定为 undefined

② 如果是函数声明,要记录函数名和函数体

首先在内存记录下有一个名字,和变量名的声明此时的规则是一样的;

紧接着记录下函数体,将函数名和函数体联系在一起




练习:
console.log(a);//打印函数体
a();//'a'
var a = 10;
a();//报错,a is not function
function a(){
    console.log('a');
}
a();//报错,a is not function
console.log(a);//10


代码分析:

① 预解析,检查到有声明,变量与函数

首先预解析到有变量a存在,因此记录下a这个名字,和其值undefined;

接着预解析到有函数a声明,记录下函数名a,但是发现已经记录了一个a,因此该操作无效,将函数体与a这个名字相关联,解析完毕。

② 开始逐步执行代码

赋值语句,执行给a重新赋值为10,将存储的关联函数覆盖;

执行console.log打印,打印出a的值,由于a中存储的是数字10,因此打印10

③ 分析完代码后,将上述代码转换成下列形式

(注意:不是所有代码都可以这样转换)