●预解析 其实就是聊聊 js 代码的编译和执行
●js 是一个解释型语言,就是在代码执行之前,先对代码进行通读和解释,然后在执行代码
●也就是说,我们的 js 代码在运行的时候,会经历两个环节 解释代码 和 执行代码
●JavaScript引擎在对JavaScript代码进行解释执行之前,会对JavaScript代码进行预解析,在预解析阶段,会将以关键字var和function开头的语句块提前进行处理
●处理过程:当变量和函数的声明处在作用域比较靠后的位置的时候,变量和函数的声明会被提升到作用域的开头。
解释代码和执行代码
●因为是在所有代码执行之前进行解释,所以叫做 预解析(预解释)
●需要解释的内容有两个
○var 关键字
■在内存中先声明有一个变量名
■会把 var 关键字声明的变量进行提前说明, 但是不进行赋值
○声明式函数
■在内存中先声明有一个变量名是函数名,并且这个名字代表的内容是一个函数
■也就是会把函数名进行提前声明, 并且赋值为一个函数
解析var关键字
// 1. 解析 var 关键字
console.log(num)
var num = 100
console.log(num)
代码分析:
预解析
var num
告诉浏览器, 我定义了一个叫做 num 的变量, 但是没有赋值
代码执行
第 1 行代码, 在控制台打印 num 变量的值
因为预解析的时候, 已经声明过 num 变量, 只是没有赋值
num 变量是存在的
打印出来的是 undefined
第 2 行代码, num = 100
给已经定义好的 num 变量赋值为 100 这个数据
第 3 行代码, 在控制台打印 num 变量的值
因为第 2 行代码的执行, num 已经被赋值为 100 了
此时打印出来的内容是 100
解析赋值式函数
●赋值式函数会按照 var 关键字的规则进行预解析
fn()
var fn = function() { console.log('fn 函数') }
fn()
○代码分析:
预解析
var fn
告诉浏览器我定义了一个叫做 fn 的变量, 但是没有赋值
代码执行
第 1 行代码, fn()
拿到 fn 变量存储的值当做一个函数来调用一下
因为 fn 只是声明了变量, 并没有赋值, 所以 fn 是一个 undefined
我们做的事情是, 把 undefined 当做一个函数来调用
报错: fn is not a function
解析声明式函数
//解析声明式函数
fn()
function fn() { console.log('fn 函数') }
fn()
○代码分析 :
预解析
function fn() { console.log('fn 函数') }
告诉浏览器, 我定义了一个 fn 变量, 并且 fn 变量保存的内容是一个函数
代码执行
第 1 行代码, fn()
拿到 fn 变量存储的值, 当做一个函数来调用
因为预解析阶段 fn 存储的就是一个函数
调用没有问题
第 3 行代码, fn()
拿到 fn 变量存储的值, 当做一个函数来调用
因为预解析阶段 fn 存储的就是一个函数
调用没有问题
预解析优先级
fn()
console.log(num)
function fn() {
console.log('我是 fn 函数')
}
var num = 100
●经过预解析之后可以变形为
function fn() {
console.log('我是 fn 函数')
}
var num
fn()
console.log(num)
num = 100
预解析中重名问题
1.当你使用 var 定义变量 和 声明式函数 重名的时候, 以 函数为主
2.只限于在预解析阶段, 以函数为准
案例1
num()
var num = 100
num()
function num() { console.log('我是 num 函数') }
num()
○代码分析 :
预解析
var num
告诉浏览器我定义了一个叫做 num 的变量, 但是并没有赋值
function num() { console.log('我是 num 函数') }
告诉浏览器我定义了一个叫做 num 的变量, 并且赋值为一个函数
预解析结束阶段, num 变量存在, 并且是一个函数
执行代码
第 1 行代码, num()
拿到 num 的值当做一个函数来调用
因为预解析阶段, num 就是一个函数
所以正常调用
第 2 行代码, num = 100
给 num 变量赋值为 100
因为 num 本身保存的是一个函数, 现在赋值为 100
就把 函数 覆盖了, 一个变量只能保存一个值
从此以后, num 就是 100 了
第 3 行代码, num()
拿到 num 的值当做一个函数来调用
因为第 2 行的代码执行, 已经把 num 赋值为 100
此时就是把 数字 100 当做一个函数来调用
报错: num is not a function
案例2
num()
function num() { console.log('我是 num 函数') }
num()
var num = 100
num()
○代码分析:
预解析
function num() { console.log('我是 num 函数') }
告诉浏览器, 我定义了一个叫做 num 的变量, 并且赋值为一个函数
var num
告诉浏览器, 我定义了一个叫做 num 的变量, 但是没有赋值
预解析结束的时候, num 变量存在, 并且是一个函数
代码执行
第 1 行代码, num()
把 num 存储的值拿来当做一个函数调用
因为预解析阶段, 确定了 num 就是一个函数
调用没有问题
第 3 行代码, num()
把 num 存储的值拿来当做一个函数调用
因为预解析阶段, 确定了 num 就是一个函数
调用没有问题
第 4 行代码, num = 100
把 num 赋值为 100
本身保存的函数就被覆盖了
从此以后, num 就是 100 了
第 5 行代码, num()
把 num 存储的值拿来当做一个函数调用
因为第 4 行代码的执行, 导致 num 是一个 数字 100
把 数字 100 当做函数调用
报错: num is not a function
预解析中特殊情况
●在代码中, 不管 if 条件是否为 true, if 语句代码里面的内容依旧会进行预解析
//预解析的特殊情况
// 1. if语句
console.log(num) // undefined
if (true) {
// 第一件事: var num
// 第二件事: num = 100
var num = 100
}
console.log(num)
函数体内, return 后面的代码虽然不执行, 但是会进行预解析
//预解析的特殊情况
// 2.return后面
function fn() {
console.log('我是 fn 内的代码')
console.log(num) // undefined
return
// 第一件事: var num
// 第二件事: num = 100
var num = 100
console.log(num)
}
fn()