变量的预解析
预解析呢,也被称为预解释;他对于我们初学者来说,还是蛮重要的,因为他涉及到了我们js代码的执行机制。“预解析”,这个“预”,我们会联想到“预备”、“预先”;而javascript 是一个解释型语言,所以可以理解为在代码开始执行之前,会对代码进行通读解释,然后在进行执行。所以,当我们写完代码,打开浏览器的时候,代码已经执行了,或者说这个解释的过程已经过去了,那么,这个过程,他解释了什么内容呢?
什么情况预解析
1、var关键字
在代码执行之前,会把代码里面所有的 var 关键字声明的变量提升
比如说
console.log(num) // undefined
var num = 100
在这个代码块中,运行console.log(num)之前;会将页面整个代码通读解释一下,看是否有var关键字;我们发现是有的,所以在代码执行之前,先告诉浏览器num这个变量可以使用,只不过不赋值;也就是我们常说的声明提前;所以上面的两行代码,其实等价于
var num
console.log(num)
num = 100
2、声明式函数
在代码执行之前,会把代码里面的 声明式函数的变量 提升,并且给这个变量赋值为一个 函数的地址
举个例子
fn()
function fn() {}
在代码fn()执行之前,浏览器已经知道了 fn 变量可用;并且 fn 变量的值是一个函数的地址;这些是浏览器已经通读解释好了的,所以这个时候,在function fn() {}上方调用函数是没有问题的,这也是声明式函数可以在上方调用的原因。
值得注意的是赋值式函数
赋值是式函数按照 var 关键字的解析规则解析
比如说:
fn()
var fn = function () {}
在代码执行之前,浏览器先通读解释,遇见了var关键字,知道了 fn 这个变量可用,仅此而已 在执行fn()这句代码的时候,fn 只是一个变量,还没有赋值,是 undefined
console.log(fn)//undefined
fn()
var fn = function () {}
但是()是函数执行,所以fn()这样子,是把 fn 当作函数来执行了;那么就会报错 fn is not a function!!所以赋值式函数是不能在上方调用的,因为那个时候,他还不是一个函数。
函数预解析
函数内部的预解析,是比较常见的,我们通过三个案例来更清楚的认识了解它。
案例一:
fun()
var fn = function () {
console.log('我是 fn 函数')
}
function fun() {
console.log('我是 fun 函数')
}
fn()
fn = 100
fn()
上述代码,是怎样运行的呢?首先,在代码执行之前,我们先预解析:
1. 我们找到了var关键字,所以知道全局声明一个 fn 变量可用
2. 我们看到了声明式函数,所以知道全局声明一个 fun 变量可用,并且这个变量的值是一个函数的地址
3. 预解析完成,开始执行代码
3-1、fun() 这个代码执行,因为我们上方已经预解析知道fun这个变量可用,并且是一个函数地址,所以直接执行这个函数,控制台打印出 “我是 fun 函数”
3-2、然后执行fn = function () {console.log('我是 fn 函数')}这块代码,给fn赋值;把一个函数的地址给到了 fn 这个变量
3-3、再之后,执行 fn()。可以直接调用函数,控制台打印“我是 fn 函数”
3-4、紧接着,执行fn = 100;也就是给 fn 这个变量重新赋值为 100
3-5、最后执行 fn()这行代码 那么就会报错 fn is not a function
案例二:
fn()
function fn() {
console.log('我是一个 fn 函数')
}
fn()
var fn = 100
fn()
这个案例中,变量名和函数名重复了,那应该是什么样子的呢?
我们先预解析
1. 首先,我们看到了声明式函数,所以全局声明一个 fn 变量可用,并且赋值为一个函数的地址
1. 紧接着,我们看到了var关键字,所以全局声明一个 fn 变量可用;请注意这个没有赋值
但是我们在第一步的时候,已经知道有一个fn变量可用;所以第二句话就没有什么用了。
2. 预解析完成,开始执行代码
3-1、我们代码第一步执行fn();此时 fn() 是一个函数的地址,执行函数
3-2、 我们代码第二步执行fn();此时fn() 还是一个函数的地址,函数执行
3-3、 我们代码第三步,执行fn = 100;给 fn 从新赋值,赋值为 100;从此时开始,fn不是一个函数了,是一个数值
3-4、我们代码第四步执行fn();把数值当成函数,就会报错 fn is not a function
所以当函数名和声明的变量名同名的时候,var 的声明就没有意义了
案例三:
function fn(a) {
console.log('我是 fn 函数')
a()
function a() {
console.log('我是函数 a')
}
}
fn(10)
这个案例,我们聊一下函数在执行阶段,都做了哪些事情
首先我们要明确一件事情,那就是预解析会解析函数外部的内容,不会解析函数内部的内容
那么,我们回顾一下函数的执行过程
- <!--*按照函数名称的地址找到函数*-->
- <!--*行参赋值*-->
- <!--*函数内部的代码进行预解析*-->
- <!--*把函数体内存储的代码拿出来执行一下*-->
然回顾了函数的执行过程之后,我们来分析上方案例三的代码,首先 ,全局预解析
1.在全局下,我们看到了声明式函数fn,所以知道先 声明一个 fn 变量可用,并且 fn 的值是一个函数地址
2.预解析完成,开始执行代码
2-1、 执行这行代码fn(10);然后就是函数的执行过程
2-2、 函数的执行过程
2-2-1、形参赋值 , 先给 a 赋值为一个数字 10
2-2-2、函数内部的代码进行预解析,声明一个 a 变量可用,并且赋值为一个函数的地址;所以函数体内的代码在一开始执行的时候 a 就是一个函数地址
2-3、 函数体内的代码执行,也就是执行a()这行代码,因为我们在2-2-2的时候,a就是一个函数地址了,所以我们会在控制台打印'我是函数 a'
预解析的无节操
1. 不管 if 条件是否成立,代码块里面的 var 都会进行声明
2. return 后面的代码虽然不会执行,但是会进行预解析
举个例子
function fn() {
console.log(num1)
return
var num1 = 100
}
fn()
console.log(num)
if (false) {
var num = 100
}
在上述代码中,我们会先去预解析
1. 首先,我们看到了声明式函数,所以全局声明一个 fn 变量可用,并且赋值为一个函数的地址
1. 紧接着,我们看到了var关键字,所以全局声明一个 num 变量可用
2. 预解析完成,开始执行代码
3-1、先执行fn()这行代码,然后就是函数的执行过程
3-1-1、直接就是函数内部的预解析,正常情况,return后面的代码是不执行的,但是预解析他没有节操,还是大大咧咧的开始进行自己的骚操作;声明了一个变量num1可用
3-1-2、函数内部代码执行 ,也就是执行console.log(num1)折行代码,那么结果就是undefined
3. 执行下一行代码console.log(num);因为在预解析的时候,我们已经知道有一个num变量可用;所以结果是undefined。
4. 因为选择分支结构中,条件表达式为false,所以不会再进行下面的num赋值操作了。
这个就是预解析的无节操,概括的说,就是上述的两点,不管 if 条件是否成立,代码块里面的 var 都会进行声明,return 后面的代码虽然不会执行,但是会进行预解析
相关推荐HOT
更多>>你需要深入了解一下JavaScript的new Function
JavaScript技术一直处于不断发展壮大中,如果你是前端开发人员或者JavaScript开发工程师,那么,今天这个知识点,你有必要认真了解一下,它就是...详情>>
2023-01-31 17:57:17理解React Virtual DOM
文件模型(Document Object Model,DOM) HTML、XML 和 SVG 文件的程序介面。它提供了文件(树)的程序的文件表示方法,并定义了访问并改变文件架构...详情>>
2023-01-31 17:55:42拿到就能用的25个JavaScript代码
JavaScript 有很多单行代码的实用例子,它们可以做很多强大的事情,无论你是 JavaScript 新手还是经验丰富的开发人员,学习些新东西总是好的。详情>>
2023-01-31 17:52:25CSS字体和字号
在浏览器里验证一下,字体大小果然没有发生变化!除了em,还可以使用百分比 (%) 这个单位,它是相对于父元素的大小来计算文本尺寸的。比如定义 p...详情>>
2023-01-30 16:03:02