资讯专栏INFORMATION COLUMN

深入挖掘js之作用域闭包

xiangchaobin / 922人阅读

摘要:前提中闭包无处不在,你只需要能够识别并拥有它。一实质问题当函数可以记住并访问所在的词法作用域是,就产生了闭包。依然持有该作用域的引用。延迟函数的回调会在循环结束时才执行。每个延迟函数都会讲在每次迭代中创建的作用域封闭起来。

前提:JavaScript中闭包无处不在,你只需要能够识别并拥有它。闭包是基于词法作用域书写代码时自然产生的结果。

一、实质问题

当函数可以记住并访问所在的词法作用域是,就产生了闭包。有的人会很好奇,什么是词法作用域,接下来我给大家普及一下什么是词法作用域。

词法作用域

简单的来说词法作用域就是定义在词法阶段的作用域,换就话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的

function foo(a){
    var b = a*2;
    function bar(c){
        console.log(a,b,c);
    }
    bar (b*3);
}
foo(2);

在这个例子中包含了三个逐级嵌套的作用域

1、包含整个全局作用域,foo

2、包含着foo所创建的作用域,a , bar , b

3、包含着bar所穿件的作用域 ,c

关于词法作用域我们就现讲这么多,接下来还是回到我们的正文,作用域闭包

function foo(){
    var a=2;
    function bar(){//bar()的词法作用域能够访问foo()的内部作用域
        console.log(a);
    }
    return bar;//将bar()函数当做一个值类型进行传递
}
var baz =foo();
baz(2);

foo()内部作用域依然存在,没有被回收。bar()依然持有该作用域的引用。这个引用就叫闭包

function foo(){
    var a=2;
    function baz(){
        console.log(a);
    }
    bar(baz);
}

function bar(fn){
    fn();
}
foo();
//把内部函数baz传递给bar,
// 当调用这个内部函数,
// 他涵盖的foo()内部作用域的闭包就可以观察到了,因为它能够访问a
var fn;
function foo(){
    var a =2;
    function baz(){
        console.log(a);
    };
    fn = baz;
}

function bar(){
    fn();
}
foo();
bar();

无论通过何种手段将内部函数传递到所在的词法作用域以外,他都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。

二、提升
function wait(message){
    setTimeout(function timer(){
        console.log(message)
    },1000);
};
wait("hello world");

在引擎内部,内置的工具函数setTimeout()持有对一个参数的引用,引擎会调用这个函数,在这个例子中就是内部的timer函数,而词法作用域就在这个过程中保持完整。这就是闭包。

三、循环和闭包
for(var i=0;i<=5;i++){
    setTimeout(function timer() {
        console.log(i);
    }, i*1000);
}
//大家猜猜结果会是啥?

正常情况下会分别输出数字1~5,但实际会输出五次6。

延迟函数的回调会在循环结束时才执行。可以想象一下异步加载机制。因此settimeout每次要等到循环结束后才显示值,这样就得到了我们的结果,输出了五次6。

代码中有什么缺陷导致它的行为通语义所暗示的不一致呢?
我们需要更多的作用域,特别是在循环的过程中每个迭代都要一个闭包作用域,因此想到了立即执行函数

for( var i=0;i<=5;i++){
    (function(){
        setTimeout(function timer() {
        console.log(i);
    }, i*1000);
    })();
}

这样子为什么还不行呢?我们显然拥有了更过的词法作用域。
每个延迟函数都会讲IIFE在每次迭代中创建的作用域封闭起来。

如果作用域是空的话,我们的IIE只是一个什么都没用的空作用域。

for( var i=1;i<=5;i++){
    (function(){
        var j =i;
        setTimeout(function timer() {
        console.log(j);
    }, j*1000);
    })();
}
重返块作用域
for(let i =1;i<=5;i++){
    
    setTimeout(function timer() {
        console.log(i);
    }, i*1000);
}

let欺骗此法作用域,每次在迭代都去创建一个新的作用域,然后执行完后被销毁,这样每个迭代都有自己的作用域就可以达到我们的预期效果,输出1~5。

四、模块
function coolModule(){
    var something = "cool";
    var another = [1,2,3];
    function doSomething(){
        console.log(something);
    }
    function doAnother(){
        console.log(another.join("!"));
    }
    return {
        doSomething: doSomething,
        doAnother: doAnother
    };
}

var foo = coolModule();

foo.doAnother();
foo.doSomething();

这个模式JavaScript中被称为模块,保护私有属性,只提供公共方法。

模块模式需要具备两个必要条件:

1、必须有外部的封闭函数

2、封闭函数必须返回至少一个内部函数

现代的模块机制

大多数模块依赖加载器/管理器本质上都是将这种模块定义封装进一个友好的API。

var MyModules = (function Manager(){
            var modules = {};
            function define(name,deps,impl){
                for(var i=0;i           
               
                                           
                       
                 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107700.html

相关文章

  • 深入挖掘js函数

    摘要:通过可取可取的他们所属对象的上下文的方法称为公共方法函数调用模式当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的,以此模式调用函数,被绑定到了全局对象。 前言: 前端这两年的新技术铺天盖地,各种框架、工具层出不穷眼花缭乱。最近打算好好复习下 js 基础,夯实的基础才是学习新技术的基石。本文作为读书笔记简单的总结下 js 函数的基础知识。 一、函数对象 JavaScr...

    douzifly 评论0 收藏0
  • 【进阶2-1期】深入浅出图解作用链和闭包

    摘要:本期推荐文章从作用域链谈闭包,由于微信不能访问外链,点击阅读原文就可以啦。推荐理由这是一篇译文,深入浅出图解作用域链,一步步深入介绍闭包。作用域链的顶端是全局对象,在全局环境中定义的变量就会绑定到全局对象中。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周开始前端进阶的第二期,本周的主题是作用域闭包,今天是第6天。 本...

    levius 评论0 收藏0
  • 【进阶2-3期】JavaScript深入闭包面试题解

    摘要:闭包面试题解由于作用域链机制的影响,闭包只能取得内部函数的最后一个值,这引起的一个副作用就是如果内部函数在一个循环中,那么变量的值始终为最后一个值。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第二期,本周的主题是作用域闭包,今天是第8天。 本计划一共28期,每期重点攻克一个面试重难点,如果你还不了...

    alanoddsoff 评论0 收藏0
  • 深入贯彻闭包思想,全面理解JS闭包形成过程

    摘要:下面我们就罗列闭包的几个常见问题,从回答问题的角度来理解和定义你们心中的闭包。函数可以通过作用域链相互关联起来,函数内部的变量可以保存在其他函数作用域内,这种特性在计算机科学文献中称为闭包。 写这篇文章之前,我对闭包的概念及原理模糊不清,一直以来都是以通俗的外层函数包裹内层....来欺骗自己。并没有说这种说法的对与错,我只是不想拥有从众心理或者也可以说如果我们说出更好更低层的东西,逼格...

    snowell 评论0 收藏0
  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0

发表评论

0条评论

xiangchaobin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<