摘要:前提中闭包无处不在,你只需要能够识别并拥有它。一实质问题当函数可以记住并访问所在的词法作用域是,就产生了闭包。依然持有该作用域的引用。延迟函数的回调会在循环结束时才执行。每个延迟函数都会讲在每次迭代中创建的作用域封闭起来。
前提: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
...链,点击阅读原文就可以啦。 推荐理由 这是一篇译文,深入浅出图解作用域链,一步步深入介绍闭包。看完本文对于相关知识的逻辑会清晰很多。 阅读笔记 红宝书(p178)上对于闭包的定义:闭包是指有权访问另外一个函数作用...
...转发,您的支持就是我坚持的最大动力。 本期推荐文章 深入javascript——作用域和闭包 ,由于微信不能访问外链,点击阅读原文就可以啦。 推荐理由 本篇文章介绍了作用域、作用域链和闭包,然后重点介绍一个面试题的3种解...
写这篇文章之前,我对闭包的概念及原理模糊不清,一直以来都是以通俗的外层函数包裹内层....来欺骗自己。并没有说这种说法的对与错,我只是不想拥有从众心理或者也可以说如果我们说出更好更低层的东西,逼格会提升...
...t 的 Object.defineProperty() 函数 JavaScript 基础要搞好 Javascript 深入浅出原型 JavaScript 使用 prototypal 原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。 JavaScript 特殊对象 Ar...
阅读 421·2021-10-09 09:44
阅读 890·2021-09-22 15:54
阅读 4510·2021-09-22 10:55
阅读 1200·2019-08-29 18:41
阅读 556·2019-08-29 11:24
阅读 1860·2019-08-28 18:20
阅读 811·2019-08-26 11:51
阅读 2777·2019-08-26 11:00