文章目录
一、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>
执行结果 :
三、函数预解析
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>
执行结果 :
四、函数表达式预解析
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>
执行结果 :