当前位置:网站首页>JS什么是声明提前?函数与变量声明提前的先后顺序(执行上下文铺垫篇)
JS什么是声明提前?函数与变量声明提前的先后顺序(执行上下文铺垫篇)
2022-07-27 13:14:00 【行星飞行】

壹 * 引
ES6中因为const let的变量声明方式,以及暂时性死域的作用,声明提前这个问题已经得到很大的改善了。但考虑到不同公司面试水平参差不齐,也许还是有公司会考ES5中的声明提前,因此本文重点在于解释这个概念,以及变量与函数提升的顺序是怎么样的。另外,声明提前的本质是执行上下文在作怪,你可以先了解声明提前,之后再阅读博主执行上下文文章,那么本文开始。
贰 * 从一道面试题说起
console.log(a)//?
a();//?
var a =3;
function a(){
console.log(10);
}
console.log(a);//?
a = 6;
a();//?
四处分别输出什么?为什么?读完本文,最少也能在你心中激起一丝波澜了。
叁 * 什么是变量声明提前
先来了解一个函数作用域的概念:**变量在声明它们的函数体以及这个函数体嵌套的任意函数体内始终可见。**说直白点,在声明一个变量的前后,你都可以直接使用它,并不会报错。举个例子:
(function(){
console.log(a);//undefined
var a ="听风";
console.log(a);//听风
}())
前面已经说了,变量在声明它们的函数体内始终可见,尽管第一个console输出在声明a之前,但它依旧能输出,并不会报错,那是因为声明统一提前,赋值原地不变。上面代码等同于:
(function(){
var a;
console.log(a);//声明了但未赋值,所以输出undefined;
a ="听风";
console.log(a);//上一步赋值了,所以输出 听风
}())
声明提前了,只是没有赋值,赋值仍保留远处不变,所以说变量a在function每一处都是可用的,就是这么个怪逻辑。
肆 * 什么是函数声明提前(函数体提前)
函数声明提前的原理与变量声明提前情况类似,需要提醒的是,只有函数声明格式的函数才会存在函数声明提前,比如函数表达式,构造函数,都不存在函数声明提前。
函数创建的三种写法:
a.函数声明:function fn(a){ console.log(a) };(只有这个家伙存在函数声明提前)
b.函数表达式:var fn = function(a){ console.log(a) };
c.构造函数:var fn = new Function( "a", console.log(a) );
直接上个例子:
num()//1
console.log(num)//函数本身
function num(){
console.log(1);
}
num();//1
console.log(num)//函数本身
有疑问的应该就是函数之前的函数调用与console了,前面说过了,函数声明的情况与变量声明类似,你可以理解为,在同一作用域内函数声明后,此函数会跑到本作用域的最前面。上面的代码等同于:
function num(){
console.log(1);
}
num()//1
console.log(num)//函数本身
num();//1
console.log(num)//函数本身
那么再来看看函数表达式是否会函数体提前:
num()//报错
console.log(num)//undefined
var num = function (){
console.log(1);
}
num();//1
console.log(num)//函数本身
第一个num()就会报错,后面三个是看不到输出的,这里是假设不受num()报错影响本应输出的情况。为什么会这样呢,还记得前面变量声明提前的原理吗,这里只是将后面的普通赋值换成了函数,所以以上代码等同于:
var num;
num()//报错,这时候都没有函数声明
console.log(num)//undefined,因为已经声明了num
num = function (){
console.log(1);
}
num();//1,有函数了啊,可以调用了
console.log(num)//函数本身,有函数了。
声明提前,赋值不变,前面只声明了num,并不存在函数,又怎么能调用num函数呢,所以第一个就报错了,这里总该明白了吧。
伍 * 变量声明提前,函数声明提前顺序
这里就有个问题了,函数声明提前,变量声明也提前,到底谁会更提的更前?假设两者都用的同一命名声明,到底最后会输出啥,我们来看个例子:
console.log(a);
var a = "听风";
function a(){
console.log("echo"); }
在解释前先引入一个概念,你不知道的JavaScript(上卷)一书的第40页中写到:**函数会首先被提升,然后才是变量。**也就是说,同一作用域下提前,函数会在更前面。以上代码等同于:
function a(){
console.log("echo");
}
var a;//由于上面函数已声明a,相同的变量名声明会被直接忽略
console.log(a);//输出函数本体
a = "听风";
为啥函数提前之后又var a;了怎么不输出undefined,因为这里只是再次声明a,并未修改现有a的值,做个简单测试就可以了:
var a=1;
var a;
console.log(a);//1
变量a已经声明过了,而且也赋值了,后面再次声明只是声明并未修改值,这种声明方式会被直接忽略,所以还是输出1.
这里讨论了变量声明提前,函数声明提前以及提前先后顺序,那么我们再回头,改写文章开头的笔试题,那么它等同于:
正确的修改:
function a(){
console.log(10);
}
var a;//再次声明a,并未修改a的值,忽略此处声明
console.log(a)//输出函数本体
a();//函数声明提前,可调用,输出10
a =3;//这里修改值了,a=3,函数已不存在
console.log(a);//输出3
a = 6;//再次修改为6,函数已不存在
a();//a已经为6,没有函数所以没法调用,直接报错
错误的修改:
var a;//再次声明a,并未修改a的值
function a(){
console.log(10);
}
console.log(a)//输出函数本体
a();//函数声明提前,调用输出10
a =3;//这里修改值了,a=3,不在是函数了
console.log(a);//输出3
a = 6;//再次修改为6
a();//a已经为6,不存在函数了,所以没法调用,报错
可能很多人的思路是,var a = 3在前,函数声明在后,var a先提前,然后函数再次提前覆盖了var a;你们也能发现上面两种改写结果都是一样的,因为我在上面的橙色解释中说了,但其实它们的提前是有固定的先后顺序的,这里希望大家能清楚。
本文只是解释了什么是变量提升,准确来说变量提升是执行上下文搞得鬼,代码在执行前都会做一番准备工作,也就是创建执行上下文,如果大家对于变量提升是何原理有兴趣,可以读读博主 一篇文章看懂JS执行上下文 这篇文章。对于你加深理解一定有所帮助。
边栏推荐
- HDU4496 D-City【并查集】
- How to view revenue and expenditure by bookkeeping software
- 微策生物IPO过会:年营收12.6亿 睿泓投资与耀合医药是股东
- Chapter3 data analysis of the U.S. general election gold offering project
- Recursive method to realize the greatest common divisor
- [training day4] sequence transformation [thinking]
- Slam overview Reading Note 7: visual and visual intangible slam: state of the art, classification, and empirical 2021
- Hdu1422 revisits the world cup [DP]
- Lighting 5g in the lighthouse factory, Ningde era is the first to explore the way made in China
- Electronic bidding procurement mall system: optimize traditional procurement business and speed up enterprise digital upgrading
猜你喜欢

Group division and characteristic analysis of depression patients based on online consultation records

线程知识总结

Converter registration of easyexcel

One of yolox improvements: add CBAM, Se, ECA attention mechanism

Named entity recognition of Chinese electronic medical records based on Roberta WwM dynamic fusion model

达科为生物IPO过会:年营收8.37亿 吴庆军父女为实控人

How to make computers have public IP

基于企业知识图谱的企业关联关系挖掘

codeforces 1708E - DFS Trees

Flexible and easy to use WYSIWYG visual report
随机推荐
Recursive method to realize the greatest common divisor
Chapter 3 business function development (view clue details)
The difference between [x for X in list_a if not np.isnan (x)] and [x if not np.isnan (x) else none for X in list_a]
初学者入门:使用WordPress搭建一个专属自己的博客
Docker实践经验:Docker 上部署 mysql8 主从复制
Group division and characteristic analysis of depression patients based on online consultation records
认知篇----硬件工程师的成才之路之经典
网上券商APP开户安全有保障吗?
Vscode -- create template file
10 practical uses of NFT
【idea】设置提取serialVersionUID
Download address of each version of libtorch
Slam overview Reading Note 4: a survey on deep learning for localization and mapping: towards the age of spatial 2020
【科普】精度和分辨率的区别与联系
微策生物IPO过会:年营收12.6亿 睿泓投资与耀合医药是股东
Cognition -- classic of the road to success of hardware engineers
GoPro access - control and preview GoPro according to GoPro official document /demo
Design of LR1 compiler based on C language
基于预训练模型的多标签专利分类研究
Leetcode · daily question · 592. fraction addition and subtraction · simulation