块级作用域中声明函数的一些小问题分析

先看一段简单代码,原题记不大清了,重新写了一个,大致如下

function fun() {
    console.log(a);
    console.log(b);
    if (true) {
        function b() { console.log("ycx") };
        var a = 10;
    }
    console.log(a);
    console.log(b);
}
fun();

初看此题,一般都会先考虑利用预编译的知识点去分析此题。
在代码执行前会先进行两步操作
第一步代码检测会检测一些明显的语法错误,并不涉及一些逻辑方面的
第二步才是预编译的过程

预编译
在函数执行前的一瞬间,生成AO对象
函数的形参作为AO对象的属性名,实参作为AO对象的属性值
分析var声明,变量名作为AO对象的属性名,属性值为undefined,遇到和参数同名的情况,不做任何改变
分析函数声明,函数名作为AO的属性名,属性值为函数体,遇到相同属性名,直接覆盖

若直接按照上面预编译的步骤进行分析,可得fun.AO

fun.AO = {
    a: undefined,
    b: function() { console.log("ycx") },
}

然后得到答案

// undefined
// function() { console.log("ycx") }
// 10
// function() { console.log("ycx") }

咋一看合情合理,但是放到浏览器里面跑一遍
在这里插入图片描述

运行结果与预先估计的不太对

问题就出在if条件里面的函数声明,似乎并没有被提前
实际上在这里的函数声明并没有完全提前,只是提前了声明部分,并没有分配实际的内存空间

在ES5的标准中,块级作用域中是不允许声明函数的
但是浏览器在解析的过程中,为了兼容旧的代码,并没有遵守这一规定,因此上面代码在执行的时候至少是没有报错的

在执行的时候,函数声明会转换为函数表达式
if语句中会转换成类似于以下代码

if (true) {
        var b = function() { console.log("ycx") };
        var a = 10;
    }

原题可以转换为

function fun() {
    console.log(a);
    console.log(b);
    if (true) {
        var b = function() { console.log("ycx") };
        var a = 10;
    }
    console.log(a);
    console.log(b);
}
fun();

此时,很容易便能得到与浏览器运行结果相同的结果

if有相同效果的块级作用域还有

for循环
function fun() {
    console.log(a);
    console.log(b);
    for (var i = 0; i < 10; i++) {
        function b() { console.log("ycx") };
        var a = 10;
    }
    console.log(a);
    console.log(b);
}
fun();
// undefined
// undefined
// 10
// function() { console.log("ycx") }
try catch
function fun() {
    console.log(a);
    console.log(b);
    try {
        function b() { console.log("ycx") };
        var a = 10;
    } catch (error) {

    }
    console.log(a);
    console.log(b);
}
fun();
// undefined
// undefined
// 10
// function() { console.log("ycx") }
甚至是一个{ }
function fun() {
    console.log(a);
    console.log(b);
    {
        function b() { console.log("ycx") };
        var a = 10;
    }
    console.log(a);
    console.log(b);
}
fun();
// undefined
// undefined
// 10
// function() { console.log("ycx") }
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值