详解函数和变量的声明提升

详细解读—函数和变量的声明提升
一 - 声明提升常见面试题
☛我们先以几道面试题开头来引入,
☛大家可以先给自己做出一个答案,然后再看文章的思路捋一捋哟。

来一道基础的吧~

var a=“Hello”;
function test(){
alert(a);
var a=“World”;
alert(a);
}
test();
1
2
3
4
5
6
7
难度+1

var a = 1;
function outer(){
a = 2;
function inner(){
alert(a);
a = 4;
}
inner();
}
outer();
alert(a);
1
2
3
4
5
6
7
8
9
10
11
继续加油

(function(){
f1();
f2();
var f1 = function(){};
function f2(){
alert(1);
}
})();
1
2
3
4
5
6
7
8
最后一道

(function () {
console.log(a);
var a=1;
function a() {
console.log(“biu~”);
}
})()
1
2
3
4
5
6
7
二 - 究竟什么是声明提升?
引擎在解释JS代码之前,首先要对JS代码进行编译,其中编译的一部分工作就是找到所有的声明,包括变量和函数的所有声明都会在任何代码被执行前首先被处理。
var a = 1这句话会被浏览器读成 var a和a = 1两句话执行,其中var a会在编译阶段就先执行了,而a = 1这段赋值代码会在原地等待执行阶段。
console.log(a);
var a = 2;
1
2
上边这段代码,如果代码按照顺序由上自下执行,那么执行到console.log(a);时,a还没有声明,所以会包一个找不到变量a的错,但是事实上,这句话打印了一个undefined,说明a被声明了,但是没有被赋值,那么结合上一段的文字,我们可以得出代码实际运行的是这样的:

var a;
console.log(a);
a = 2;
1
2
3
三 - 函数的提升
大家可能在书写代码的时候发现,无论函数封装写在前或者后,我们的函数调用都可以顺利执行。

fn1();//可以执行
function fn1() {
console.log(“hello”);
}
1
2
3
4
为什么呢?其实函数声明,包括函数的代码块都i会被提升,所以调用函数的时候,函数声明已经被执行过了。

但是有个案例大家了解一下:

fn2();//报错,fn2不是一个函数
var fn2 = function () {
console.log(“world”);
}
1
2
3
4
我们可以看到 以给匿名函数赋值的形式定义函数,只会提升函数声明,但是函数表达式却不会被提升。因为变量fn2被提升,但是并没有赋值,我们书写的fn2()无法运行,而抛出了异常。
以下就是实际执行的顺序:

var fn2;
fn2();
fn2 = function () {
console.log(“world”)
}
1
2
3
4
5
函数优先提升
我们都知道了,函数声明和变量声明都会被提升,那么遇到这样的情况会怎么办?

fn3();
var fn3=function () {
console.log(“fn3-1”);
}
fn3();
function fn3() {
console.log(“fn3-2”);
}
1
2
3
4
5
6
7
8
哎呦,嘛情况,突然迷了!!!
☛ 这个时候你就要考虑,同样的一个变量名称,到底是把var fn3给先提声上去,再提升 fn3函数体?还是先提升 fn3函数体,再提升var fn3???其实都不对!!!

☛ 答案是:函数会被优先提升,但后才是变量提升,但是当函数提升后,然后发现还有一个变量声明和函数声明一样的名称,这个就是重复声明,那么这个var fn3 是不生效直接忽略的。

所以实际代码运行顺序是:

function fn3() {
console.log(“fn3-2”);
}
fn3();//fn3-2
fn3=function () {//var fn3因为重复声明被忽略
console.log(“fn3-1”);
}
fn3();//fn3-1
1
2
3
4
5
6
7
8
当然,我们还是建议再同一个作用域重复声明是很烂的选择

说在最后
再代码作用域中的声明,都会在代码执行前被首先处理,所有的声明都会被移动到各自作用域的最顶端,这个过程就叫做声明提升。

四 - 答案:
问题1:

var a=“Hello”;
function test(){
alert(a);
var a=“World”;
alert(a);
}
test();

实际执行:
var a=“Hello”;
function test(){
//作用域有声明a,声明提升到这里
var a;
alert(a);//本作用域声明a,所以不去使用父作用域的a,但是本作用域的a没有赋值,所以弹出undefined
a=“World”;
alert(a);//赋值后 ,弹出world
}
test();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
问题2:

var a = 1;
function outer(){
a = 2;
function inner(){
alert(a);
a = 4;
}
inner();
}
outer();
alert(a);

执行结果:

var a = 1;
function outer(){
a = 2;
function inner(){
//本作用域没有声明a,所以没有任何提升,直接执行
alert(a); // 所以弹出 a为 2
a = 4;
}
inner();
}
outer();
alert(a);//只有全局声明了a,所以所有作用域使用的都是全局的a,所以a最后被赋值为4 弹出4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
问题3

(function(){
f1();
f2();
var f1 = function(){};
function f2(){
alert(1);
}
})();
实际执行结果:

(function(){
function f2(){
alert(1);
}
var fn1;
f1();//提升后先执行fn1(),但是fn1被提升的是变量不是函数,所以这里报错,不是一个函数
f2();//上一句话报错,这句话不再运行
f1 = function(){};
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
问题4:

(function () {
console.log(a);
var a=1;
function a() {
console.log(“biu~”);
}
})()
实际执行结果:

(function () {
function a() {
console.log(“biu~”);
}
console.log(a);//打印了a这个函数的函数体
a=1;//因为函数有限声明提升,所以这里的var a被提升时,发现重复声明,故被忽略了var a;
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

————————————————
版权声明:本文为CSDN博主「拎着蜗牛跑的壳儿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/azxqwe123/article/details/103329541

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值