最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 你不知道的作用域

    正文概述 掘金(锋享前端)   2021-01-25   496

    如果你是一个前端工程师,那么JavaScript的作用域你一定不会陌生。

    你知道的可能是 JavaScript中有

    • 传统的函数级作用域 和 全局作用域
    • ES6 let const 的块级作用域

    但是还有一个你不知道的块级作用域的存在,今天我们就来扒一扒这些鲜为人知的小秘密

    我们先来看看下面这个段代码,请思考一下结果是什么。

    function fn() {
        var foo = 1;
        if (true) {
            foo = 2;
            function foo() {}
            foo = 3;
            console.log(foo);
        }
        console.log(foo); 
    }
    
    fn();
    

    想必你心中已经有了结果

    你答对了吗?答案结果是否有些意外呢?

    好了 我们来看看为什么会出现这个答案

    首先我们需要先了解以下基本知识

    声明提前

    声明提前指的是JS引擎在执行之前对代码进行的预解析(为了提高执行效率) 具体的来说就是使用(var)声明变量和(function)声明的函数正预编译阶段将其提升到了作用域的顶部

    全局变量声明

    // 全局变量在声明时将其提升到全局作用域的顶部
    console.log(foo);  // undefined
    var foo = 'test';
    
    
    // 上面代码相当于
    var foo;
    console.log(foo);
    foo = 'test';
    

    函数作用域变量声明

    // 函数内的变量在声明是将其提升到函数作用域的顶部
    function fn(){
        console.log(foo); // undefined
        var foo = 5;
    }
    fn();
    console.log(foo); // err: foo is not defined
    
    // 不同于全局变量的是 在函数中声明的变量仅提升到函数作用域的顶部
    

    函数声明

    console.log(fn);  // function fn
    
    function fn(){
        // dosomething
    }
    
    // 函数声明提升到了作用域顶部
    

    函数表达式声明

    console.log(fn);// undefined
    
    var fn = function(){}
    
    // 此处应为fn是使用var关键字声明所以按照变量声明提升的情况 变量提升不赋值 则结果为undefined
    

    函数块级作用域

    通过下面代码我们可以知道 变量的声明是没有块级作用域的,if语句块中声明的变量foo会提升到全局作用域并初始化值为undefined

    console.log(foo); // undefined
    
    if(true){
        var foo = 'test';
    }
    
    

    我们再看看函数的情况

    console.log(foo); // undefined
    
    if(true){
        console.log(foo); // function foo
        function foo(){}
    }
    console.log(foo);  // function foo
    

    上面这个例子告诉我们 函数foo提升到了if语句块的顶部,但是没有提升到全局作用域的顶部。但全局作用域中存有一个名为foo的变量 在代码执行后同步成了函数foo

    同步?为什么会有同步?我们来看看观察上帝视角的神器 ———— 断点调试

    我这边监听了 foo 变量和 window.foo 大家请注意一下它的变化

    同时我们也关注一下 Scope 作用域

    你不知道的作用域

    你不知道的作用域

    你不知道的作用域

    你不知道的作用域

    回归原题

    我们对foo变量进行隔行输出 看看结果

    function fn() {
        // 由于此处最高级别的作用域为 fn函数作用域( 此处不涉及全局作用域以及全局对象window )
        // 我们将注释中的foo 命名为 fn.foo 和 block.foo
        console.log(foo); // undefined ( fn.foo = undefined )
        var foo = 1; // 定义变量 
        console.log(foo); // 1 ( fn.foo = 1 )
        if (true) {
            console.log(foo); // function foo ( block.foo = function )  函数声明提升 
            foo = 2;
            console.log(foo); // 2 ( block.foo = 2 )  ( fn.foo = 1 )
    
            function foo() {} // 执行函数赋值 将block的foo同步到父级作用域fn  (fn.foo = 2)
            console.log(foo); // 2 ( block.foo = 2) (fn.foo = 2)
            foo = 3;
            console.log(foo); // 3 ( block.foo = 3) (fn.foo = 2)
        }
        console.log(foo); // 2 (fn.foo = 2)
    }
    
    fn();
    

    结合上面断点测试的结果大家可以发现,函数在代码块中声明会提前到块级作用域顶部,预编译结束后开始执行代码 在执行阶段任然会执行函数的赋值操作,其实是函数赋值的第二次执行(第一次在预编译阶段) 第二次的赋值执行的意义是确认当前 函数/全局 作用域能准确的检索到函数 所以讲函数同步到了 当前的函数或全局作用域中。

    好了本次解析就到这里,还有不明白的小伙伴可以copy代码去进行断点测试,相信很快你能理解其中奥秘。 关注我 学更多前端知识。下次再见。


    起源地下载网 » 你不知道的作用域

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元