什么是闭包

闭包是javaScript语言的一种特性,在 javaScript 中以函数作为承接单元。当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

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

bar() 产生了闭包,但是由于它内嵌在foo函数里面执行,bar中对a的引用遵循了词法作用域的查找规则,其实也是闭包查询规则的一部分。

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

稍微修改一下上面的代码,将bar return 出来,在foo函数外执行,bar依旧可以获取到a,而这时候bar它记住了foo的内部词法作用域,并且可以按照词法作用域查询规则找到a。由此可想bar能够引用foo的内部作用域,说明foo的内部作用域并没有被回收,而正因为闭包的存在,引擎没有回收foo的内部作用域的内存空间。

回调函数

function foo() {
var a = 2;
function baz() {
console.log( a ); //
}
bar( baz );
}
function bar(fn) {
fn(); // fn是一个闭包!
}

对函数类型的值进行传递,会形成一个闭包,所以常见的回调函数采用了闭包,如:

function wait(message) {
setTimeout( function timer() { console.log( message );
}, 1000 ); }
wait( "Hello, closure!" );

setTimeout中的内部函数timer是一个具有 wait的作用域的闭包。

在定时器、事件监听器、 Ajax 请求、跨窗口通信、Web Workers 或者任何其他的异步(或者同步)任务中,只要使 用了回调函数,实际上就是在使用闭包。

模块

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.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

CoolModule()通过return 出一个对象,包含其两个内部函数,而两个内部函数是包含着CoolModule的内部作用域的闭包。

模块的特点:

  • 为创建内部作用域而调用了一个包装函数;

  • 装函数的返回 值必须至少包括一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的 闭包。

单例模块

var foo = (
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
};
})();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

通过内部函数修改内部私有变量的值

var foo = (function CoolModule(id) {
function change() {
// 修改公共 API
publicAPI.identify = identify2; }
function identify1() {
console.log( id );
}
function identify2() {
console.log( id.toUpperCase() );
}
var publicAPI = {
change: change,
identify: identify1
};
return publicAPI;
})( "foo module" );
foo.identify(); // foo module foo.change();
foo.identify(); // FOO MODULE

模块依赖加载器

var MyModules = (
function Manager() {
var modules = {};
function define(name, deps, impl) {
for (var i=0; i<deps.length; i++) {
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply( impl, deps );
}
function get(name) {
return modules[name];
}
return {
define: define,
get: get
};
})();
MyModules.define( "bar", [], function() {
function hello(who) {
return "Let me introduce: " + who;
}
return {
hello: hello
};
} );
MyModules.define( "foo", ["bar"], function(bar) {
var hungry = "hippo";
function awesome() {
console.log( bar.hello( hungry ).toUpperCase() );
}
return {
awesome: awesome
};
} );
var bar = MyModules.get( "bar" );
var foo = MyModules.get( "foo" );
console.log(
bar.hello( "hippo" )
); // Let me introduce: hippo
foo.awesome(); // LET ME INTRODUCE: HIPPO

ES6 模块机制

// bar.js
function hello(who) {
return "Let me introduce: " + who;
}
export hello; //foo.js
// 仅从 "bar" 模块导入 hello()
import hello from "bar";
var hungry = "hippo";
function awesome() {
console.log(
hello( hungry ).toUpperCase() );
}
export awesome; //baz.js
module foo from "foo";
module bar from "bar";
console.log(
bar.hello( "rhino" )
); // Let me introduce: rhino
foo.awesome(); // LET ME INTRODUCE: HIPPO

经典的循环

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

以上会依次输出 6,6,6,6,6,6,因为 setTimeout中的闭包会在循环结束后依次执行,而每一个闭包所引用的作用域都是一致的,i变量在全局作用域中。如果想要输出我们想要的结果可以加入更多的闭包如:

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

i作为变量传入闭包函数中,每个闭包函数中通过隐试的创建了自己的作用域变量j

更加简单的方法使用let

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

let 可以创建块级作用域,这样每一个循环都是一个作用域块,每个作用域互不干扰。

总结

可以说闭包在javaScript运用广泛,一个包含其封装函数内部作用域引用的函数就是一个闭包。

【你不知道的javaScript 上卷 笔记4】javaScript 中闭包的一些运用的更多相关文章

  1. 你不知道的JavaScript上卷笔记

    你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章   初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目 ...

  2. 【你不知道的javaScript 上卷 笔记3】javaScript中的声明提升表现

    console.log( a ); var a = 2; 执行输出undefined a = 2; var a; console.log( a ); 执行输出2 说明:javaScript 运行时在编 ...

  3. 读《你不知道的JavaScript(上卷)》后感-作用域闭包(二)

    github原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们, ...

  4. Javascript学习笔记1 javascript的特点

    ..对于网页而言,Javascript无处不在,对于英语不好的人它简直是噩梦般的存在,但形式所逼,今天开始着手学习!希望自己能坚持下去.从什么地方着手,我的目标是从大处着眼,从应用着眼,不抠细节,反正 ...

  5. JavaScript学习笔记(4)——JavaScript语法之变量

    一.变量可以使用短名称(比如 x 和 y),也可以使用描述性更好的名称(比如 age, sum, totalvolume). 变量必须以字母开头 变量也能以 $ 和 _ 符号开头(不过我们不推荐这么做 ...

  6. 1.2(JavaScript学习笔记)JavaScript HTML DOM

    一.DOM DOM全称为document object model(文档对象模型). 此处的文档指当前HTML文档,对象指HTML标签. 当网页被加载时,浏览器会创建页面的文档对象模型. 下面结合具体 ...

  7. Javascript学习笔记3 Javascript与BOM简介

    什么是BOM BOM是browser object model的缩写,简称浏览器对象模型 BOM提供了独立于内容而与浏览器窗口进行交互的对象 由于BOM主要用于管理窗口与窗口之间的通讯,因此其核心对象 ...

  8. 【你不知道的javaScript 上卷 笔记7】javaScript中对象的[[Prototype]]机制

    [[Prototype]]机制 [[Prototype]]是对象内部的隐试属性,指向一个内部的链接,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就 会继续在 [[Prototyp ...

  9. 【你不知道的javaScript 上卷 笔记6】javaScript中的对象相关内容

    一.创建一个对象的语法 var myObj = { key: value // ... };//字面量 var myObj = new Object(); //new myObj.key = valu ...

随机推荐

  1. OpenLayers 6 学习笔记

    这个是真的学习笔记!不是教程 转载请声明:https://www.cnblogs.com/onsummer/p/12159366.html 基于openlayers 6.x api不太好查,就基于腾讯 ...

  2. Python常用模块sys,os,time,random功能与用法,新手备学。

    这篇文章主要介绍了Python常用模块sys,os,time,random功能与用法,结合实例形式分析了Python模块sys,os,time,random功能.原理.相关模块函数.使用技巧与操作注意 ...

  3. java循环语句 总结笔记

    1.for 循环语句 语法:for(initialization;condition;iteration) public class A { public static void main(Strin ...

  4. MySql学习-4.查询1

    1.基本查询语法: select * from 表名: **注意** 1.select 后写列名,*代表是所有列:        2.列名可以用as起别名,其出现在结果集中: 3.查询多个列,之间用逗 ...

  5. Redisson源码学习之RedissonFairLock

    博客待整理,先只是把源码看了.... 后面不再备注redis中的命令含义了,这样备注写太多了不好阅读. package org.redisson; import java.util.Arrays; i ...

  6. Everspin串口串行mram演示软件分析

    Everspin在磁存储器设计,制造和交付给相关应用方面的知识和经验在半导体行业中是独一无二的.在平面内和垂直磁隧道结(MTJ)STT-MRAM位单元的开发方面处于市场领先地位.包括40nm,28nm ...

  7. 题解【CF1311F Moving Points】

    \[ \texttt{Preface} \] 赛时,把 " 任意时刻 " 理解成 " 整数时刻 " 了,看起来一脸不可做的亚子,还各种推式子. 话说我为什么觉得 ...

  8. IIS在已有站点上->添加应用程序命令

    已有站点:HTTP80 %systemroot%\system32\inetsrv\APPCMD ADD APP /SITE.NAME:"HTTP80" /path:/Redire ...

  9. react typescript react-router

    typescript 1 connected-react-router

  10. laravel orWhere

    场景描述 需要根据商品分类.商品名称和条形码这三个查询条件去取出结果集,这三者的关系是:商品分类 and (商品名称 or 条形码) 错误尝试 第一次写出来的代码是这样的: $goodsModel = ...