一、JavaScript 预解析



JavaScript 代码 是 由 浏览器 的 JavaScript 解析器 执行的 , 执行过程分如下两步 :

  • 预解析
  • 正式执行代码

JavaScript 的 " 预解析 “ 又称为 ” 变量和函数的提升 " , 会把 var 变量声明 和 function 函数声明 提升到 当前作用域 的 最前面 ;

预解析 机制 允许在代码中 , 无论实际 声明变量 / 声明函数 的位置在哪里 , 解析器 在 预解析 阶段 都会把它们提升到它们各 自的作用域的最顶部 ;





二、变量预解析




1、变量预解析 - 变量提升


变量预解析 又称为 " 变量提升 " , 就是 把 所有的 变量声明 , 提升到 当前 作用域 的 最前面 ;

在 JavaScript 中 , 使用 var 关键字声明的变量 , 会被提升到其所在的 全局作用域 或 局部作用域 的顶部 ;

注意 : 只有 变量 的声明 会被提升 , 初始化操作 不会被提升 , 如果 在声明之前尝试访问一个变量 , 只能访问到 未初始化 的变量值 undefined ;


以下面的代码为例 :

// 输出 undefined , 只有变量声明被提升 , 变量初始化在后面
console.log(num); 
// 声明变量 , 并将变量初始化为 5 
var num = 5;

var num = 5; 操作其实是两步操作 , 先声明了变量 , 在为变量初始化了数值 5 ;

var num;
num = 5;

变量提升 , 只将 变量声明 , 也就是 var num; 语句提升到了 当前作用域 的最前面 , num = 5; 初始化赋值操作 仍然在原来的位置 ;

预解析 变量提升 的效果相当于将 代码转为 :

// 声明变量
var num;
// 输出 undefined , 只有变量声明被提升 , 变量初始化在后面
console.log(num); 
// 变量初始化赋值 5 
num = 5;

2、代码示例 - 变量预解析


下面的代码中的 JavaScript 代码 , 最终执行结果与下面的代码一致 ;

JavaScript 引擎 将

// 输出 undefined , 只有变量声明被提升 , 变量初始化在后面
console.log(num); 
// 声明变量 , 并将变量初始化为 5 
var num = 5;

预解析为 :

// 声明变量
var num;
// 输出 undefined , 只有变量声明被提升 , 变量初始化在后面
console.log(num); 
// 变量初始化赋值 5 
num = 5;

代码示例 :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <!-- 设置 meta 视口标签 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JavaScript</title>
    <style></style>
    <script>
        // 预解析

        // 变量预解析 - 变量提升
        // 输出 undefined , 只有变量声明被提升 , 变量初始化在后面
        console.log(num);
        // 声明变量 , 并将变量初始化为 5 
        var num = 5;
    </script>
</head>

<body>
</body>

</html>

执行结果 :

【JavaScript】预解析 ① ( 变量预解析 - 变量提升 | 函数预解析 - 函数提升 | 函数表达式预解析 )-LMLPHP





三、函数预解析




1、函数预解析 - 函数提升


函数预解析 又称为 " 函数提升 " , 与 变量提升类似 , 使用 function 关键字 的 函数声明 也会被提升到它们所在的作用域的顶部 , 因此可以 在函数声明之前 调用该函数 ;


在下面的代码中 , 先调用了 hello 函数 , 再使用 function 关键字 声明函数 ,

        hello();

        function hello() {
            console.log("Hello");
        }

在 JavaScript 引擎 进行 预解析时 , 函数预解析 就是将 function 关键字声明的函数 , 提升到 作用域最顶端 , 因此 可以在 函数执行前调用 该函数 ;

函数预解析 后的 代码效果如下 , 调用 hello 函数 , 成功执行该函数 , 这是因为 函数预解析 过程将 函数提升到了 作用域最顶端 ;

		function hello() {
            console.log("Hello");
        }
        hello();

2、代码示例 - 函数预解析


代码示例 :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <!-- 设置 meta 视口标签 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JavaScript</title>
    <style></style>
    <script>
        // 预解析

        // 函数预解析 - 函数提升

        // 输出 Hello , 函数声明提升到 作用域最顶部
        hello();

        // 函数预解析
        function hello() {
            console.log("Hello");
        }
    </script>
</head>

<body>
</body>

</html>

执行结果 :

【JavaScript】预解析 ① ( 变量预解析 - 变量提升 | 函数预解析 - 函数提升 | 函数表达式预解析 )-LMLPHP





四、函数表达式预解析




1、函数表达式预解析


函数表达式 的 本质是一个 变量 , 只是将 函数 赋值给了 变量 ;

由于 变量预解析 时 , 只是将 var 关键字的 变量声明 提升到了 作用域的最顶端 , 变量的 初始化 仍然在原地 ;

此时 通过该 变量 调用函数 , 肯定会报错 , 因为 函数此时没有赋值给 该变量 ;


在下面的代码中 , var fun 是一个变量 , 因此这里只进行 变量的提升 ,

        // 报错 : Uncaught TypeError: fun is not a function
        fun();

        // 函数预解析
        var fun = function hello() {
            console.log("Hello");
        }

变量提升后的效果如下 :

		// 函数提升
		var fun;
		
        // 报错 : Uncaught TypeError: fun is not a function
        fun();

        // 将 函数表达式 赋值给 fun 变量
        fun = function hello() {
            console.log("Hello");
        }

上述代码执行后 , 就会报错 Uncaught TypeError: fun is not a function ;


2、代码示例 - 函数表达式预解析


代码示例 :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <!-- 设置 meta 视口标签 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JavaScript</title>
    <style></style>
    <script>
        // 预解析

        // 函数表达式 预解析情况

        // 报错 : Uncaught TypeError: fun is not a function
        fun();

        // 函数预解析
        var fun = function hello() {
            console.log("Hello");
        }
    </script>
</head>

<body>
</body>

</html>

执行结果 :
【JavaScript】预解析 ① ( 变量预解析 - 变量提升 | 函数预解析 - 函数提升 | 函数表达式预解析 )-LMLPHP

04-08 22:10