理解闭包三个基本的事实

第一个事实:js允许你引用在当前函数以外定义的变量。

function makeSandwich(){

var magicIngredient=”peanut butter”;

function make(filling){

return magicIngredient+’and ’+filling;

}

return make(‘jelly’);

}

makeSandwich();//”peanut butter and jelly”

图上直接指出如下

第二个事实:即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。

function sandwichMaker(){

var magicIngredient=”peanut butter”;

function make(filling){

return magicIngredient+’and ’+filling;

}

return make;

}

var f=sandwichMaker();

f(“jelly”);//”peanut butter and jelly”

f(“bananas”);//”peanut butter and bananas”

f(“marshmallows”);//”peanut butter and marshmallows”

还是上图标识

原理:js的函数值包含了比调用它们时执行所需要的代码还要多的信息。而且js函数值还在内部存储它们可能会引用的定义在其封闭作用域的变量。那些在其所涵盖的作用域内跟踪变量的函数被称为闭包。make函数就是一个闭包。其代码引用了两个外部变量:magicIngredient和filling。每当make被调用时,其代码都能引用到这两个变量,因为该闭包存储了这两个变量。

函数可以引用在其作用域内的任何变量,包括参数和外部函数变量。

function sandwichMaker(magicIngredient){

function make(filling){

return magicIngredient+”and ”+filling;

}

return make;

}

var hamAnd=sandwichMaker(“ham”);

hamAnd(“cheese”);//”ham and cheese”

hamAnd(“mustard”);//”ham and mustard”

var turkeyAnd=sandwichMaker(“trukey”);

turkeyAnd(“Swiss”);//”trukey and Swiss”

turkeyAnd(“Provolone”);//”trukey and Provolone”

闭包是js最优雅、最有表现力的特性之一,也是许多惯用法的核心。js还提供了一种更为方便构建闭包的字面量语法--函数表达式。

function sandwichMaker(magicIngredient){

return function(filling){

return magicIngredient+”and ”+filling;

}

}

请注意,该函数表达式是匿名的。由于只需要产生一个新值,而不需要在局部使用,所以没必要给该函数命名。

第三个事实:闭包可以更新外部变量的值。

实际上,闭包存储的是外部变量的引用,而不是它们的值的副本。因此任何具在访问这些外部变量的闭包,都可以进行更新。

function box(){

var val=undefined;

return {

set:function(newVal){val=newVal},

get:function(){return val},

type:function(){return typeof val}

}

}

var b=box();

b.type();//”undefined”

b.set(98.6);

b.get();//98.6

b.type();//”number”

这个例子里产生了一个包含三个闭包的对象。这三个闭包是set,get和type属性。它们共享访问val变量。

提示

  • 函数可以引用定义在其外部作用域的变量
  • 闭包比创建它们的函数有更长的生命周期
  • 闭包在内部存储其外部变量的引用,并能读写这些变量

后记

这个部分,这觉得这里讲得已经很清楚,如果想再深入去了解,可以去看高3上面关于闭包的讲解。

里面对作用域链,执行环境,变量对象,都有详细说明。

[Effective JavaScript 笔记] 第11条:熟练掌握闭包的更多相关文章

  1. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  2. [Effective JavaScript 笔记]第35条:使用闭包存储私有数据

    js的对象系统并没有特别鼓励或强制信息隐藏.所有的属性名都是一个字符串,任意一个程序都可以简单地通过访问属性名来获取相应的对象属性.例如,for...in循环.ES5的Object.keys()和Ob ...

  3. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  4. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  5. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  6. [Effective JavaScript 笔记]第50条:迭代方法优于循环

    "懒"程序员才是好程序员.复制和粘贴样板代码,一但代码有错误,或代码功能修改,那么程序在修改的时候,程序员需要找到所有相同功能的代码一处处进行修改.这会使人重复发明轮子,而且在别人 ...

  7. [Effective JavaScript 笔记]第19条:熟练掌握高阶函数

    高阶函数介绍 高阶函数曾经是函数式编程的一个概念,感觉是很高深的术语.但开发简洁优雅的函数可以使代码更加简单明了.过去几年中脚本语言采用了这些个技术,揭开了函数式编程的最佳惯用法的神秘面纱.高阶函数就 ...

  8. [Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑

    构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...

  9. [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合

    对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...

随机推荐

  1. 怎样写 OpenStack Neutron 的 Extension (三)

    通过上几章的介绍,我们现在的 myplugin 文件夹看上去应该是这样的: - neutron/ - plugins/ - myplugin/ - __init__.py - plugin.py - ...

  2. 获取、增加、修改、删除sqlserver字段描述

    先看添加与删除字段描述 EXEC sys.sp_addextendedproperty @name = N'MS_Description', --添加Type字段说明 @value = N'屏蔽类型对 ...

  3. 【BZOJ1013】【JSOI2008】球形空间产生器sphere(高斯消元)

    1013: [JSOI2008]球形空间产生器sphere Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1600  Solved: 860[Submi ...

  4. Boostrap响应式与非响应式

    非响应式布局 在使用非响应式布局时,在<head>标签中需要加入一下内容,其中最主要的是non-responsive.css文件 <head> <meta http-eq ...

  5. 事务四大特征:原子性,一致性,隔离性和持久性(ACID)

    一.事务 定义:所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 准备工作:为了说明事务的ACID原理,我们使用银行账户及资金管理的案例进行分析. [sql] ...

  6. .net架构设计读书笔记--第三章 第8节 域模型简介(Introducing Domain Model)

    一.数据--行为转变     很长的时间,典型的分析方法或多或少是以下两种,第一,收集需求并做一些分析,找出有关实体 (例如,客户. 订单. 产品) 和进程来实现. 第二,手持这种理解你尝试推断一个物 ...

  7. Java算法-归并排序

    归并排序采用的是递归来实现,属于“分而治之”,将目标数组从中间一分为二,之后分别对这两个数组进行排序,排序完毕之后再将排好序的两个数组“归并”到一起,归并排序最重要的也就是这个“归并”的过程,归并的过 ...

  8. SQL Server 2008 R2导出数据脚本的方法

    以前看到有些朋友说必须SQL Server 2008才能导出包含数据的脚本,后来仔细研究发现其实SQL Server 2008 R2也是可以的,只需在导出的时候在高级中设置一下即可. 1.首先在数据库 ...

  9. GMM算法k-means算法的比较

    1.EM算法 GMM算法是EM算法族的一个具体例子. EM算法解决的问题是:要对数据进行聚类,假定数据服从杂合的几个概率分布,分布的具体参数未知,涉及到的随机变量有两组,其中一组可观测另一组不可观测. ...

  10. CodeReview Learning

    目录 . 引言 . 代码检视的指导思想 . 代码检视的内容 . 回归测试 0. 引言 代码检视(Code Review)是指软件开发人员在完成代码设计.编写.调试后展开的个人或群体性的代码阅读过程,代 ...