闭包初体验 -《JavaScript面向对象编程指南》
下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理)
参考《JavaScript面向对象编程指南》
1.首先,在理解闭包之前:
我们首先应该清楚下作用域和作用域链
作用域:每个函数定义时创建时自己的环境即作用域
作用域链:函数内可访问自身和父级作用域中的变量,函数外不可访问函数内的私有变量
- var a = 1;
- function f(){
- var b = 1;
- return a;
- }
- f(); /*1*/
- b; ReferenceError: b is not defined
解读——在这里,变量a是属于全局域的,变量b的作用域就在函数f()内了,所以:
在f()内,a和b都是可见的;
在f()外,a是可见的,b则不可见;
下面是我在控制台中测试:可以更好的理解作用域链。
在outer内定义了另一个函数inner;那么在inner()中可以访问的变量既可以来自他自身的作用域,也可以来自其“父级”的作用域。这就形成了一条作用域链,该链的长度取决于我们的需要。
接下来我们就可以正式认识下闭包了:
我们通过闭包来突破作用域链的过程,也许你会发现其中的乐趣
首先我们看下下面的代码:
- var a = 'global variable';
- var F = function(){
- var b = "local variable";
- var N = function(){
- var c = "inner local"
- }
- }
我们假想全局作用域为G,我们可以将其视为可以包含一切的宇宙
然后就是本地空间F
在F内部,还有F的私有内部空间N
当我们将N的空间扩展到F以外,并且止步于全局空间内部时,就产生了一种有趣的东西 ——闭包
闭包#1
- var a = 'global variable';
- var F = function(){
- var b = "local variable";
- var N = function(){
- var c = "inner local";
- return b;
- };
- return N;
- };
- b; /*ReferenceError : b is not defined*/
- /*函数F中包含了局部变量b,因此后者在全局空间里是不可见的。*/
- N() /*ReferenceError : N is not defined*/
- /*很明显当我们在全局中调用私有函数N时,会抛出错误;我们在全局中是无法访问一个函数内的私有函数的*/
上面的代码在控制台中的返回结果:
接下来,我们在控制台中完整正确测试一次:
解读——
首先,在函数N()内部,我们是可以获得b的返回值的(来自于他的父级作用域,可以访问到),我们将b的值作为私有函数N的返回值(如果这时我们在全局中调用函数N(),仍然会抛出错误,见上面代码)
于是,我们要解决这个问题。将F的私有函数N作为F()的返回值。
接着,把函数F()赋值给另一个全局变量(实际上是将F()的返回值赋值给了一个全局变量)
从而生成了一个可以访问F()私有空间的全局函数。
- var inner = F();
- inner (); /*local variable*/
闭包#2
下面这种方法结果与之前相同,实现上略有不同。
在这里F()不在返回函数了,而是直接在函数体内创建了一个新的全局函数inner()
(首先:我们声明一个占位符,尽管这不是必须的,最好还是声明一下)
- var inner; //placeholder 占位符
- var F = function () {
- var b = "local variable";
- var N = function () {
- return b;
- };
- inner = N ;
- };
现在我们可以自行测试一下
- F(); /*undefined*/ /*想想????为什么*/
- inner(); /*local variable*/
解读——
我们在函数F()内定义了一个新的函数N(),并将它赋值给全局变量inner。
由于N()是在F()内定义的,他可以访问到F()的作用域,所以即使该函数后来升级成了全局函数,但是它依然可以保留对F()作用域的访问权
相关定义与闭包#3
接下来,我们这次使用函数参数。
我们在这里创建了一个函数,该函数将返回一个子函数,而这个子函数返回的则是父函数的参数
- function F(param) {
- var N = function () {
- return param;
- };
- param++;
- return N;
- };
我在控制台中做了测试:
发现:返回函数被调用时,param++已经执行过一次递增操作了,inner()返回的是更新后的值
由此我们可以看出:函数绑定的是作用域本身(!*!)而不是在函数定义时该作用域中的变量或当前变量所返回的值
循环中的闭包#4
我们首先看一下新手在闭包中容易犯的错误:
- function F() {
- var arr = [], i ;
- for (i=0;i<3;i++){
- arr[i] = function () {
- return i;
- };
- }
- return arr;
- }
- arr[0](); /*3*/
- arr[1](); /*3*/
- arr[2](); /*3*/
显然这并不是我们想要的结果:
在这里,我们创建了三个闭包,而三个闭包都指向了一个共同的局部变量i,
但是闭包并不会记录他们的值,他们所拥有的的只是相关作用域在创建时的一个连接(即引用)
在这个例子中,变量i恰巧存在于定义这三个函数域中。对这三个函数中的任何一个而言,当他要去获取某个值时,他会从其所在的域开始逐级寻找那个距离最近的i值。由于循环结束时i的值为3,所以这三个函数都指向了一个共同值。
我们换一种闭包的形式:(来解决这个问题)
- function F(){
- var arr = [], i ;
- for (i=0;i<3;i++){
- arr[i] = (function (x) {
- return function () {
- return x;
- }
- } (i));
- }
- return arr;
- }
- var arr = F();
- arr[0]() /*0*/
- arr[1]() /*1*/
- arr[2]() /*2*/
我们还可以定义一个正常点的函数 (不使用即时函数)来实现相同的功能。
要点是在每次迭代中,我们要在中间函数内将i的值“本地化”
- function F() {
- function binder(x){
- return function () {
- return x;
- }
- }
- var arr = [], i ;
- for (i=0;i<3;i++){
- arr[i] = binder(x);
- }
- return arr;
- }
- var arr = F()
- arr[0]() /**/
- arr[1]() /**/
- arr[2]() /**/
最后,希望自己在实战中深入理解闭包的巧妙和乐趣。
闭包初体验 -《JavaScript面向对象编程指南》的更多相关文章
- 《JavaScript面向对象编程指南(第2版)》读书笔记(一)
目录 一.对象 1.1 获取属性值的方式 1.2 获取动态生成的属性的值 二.数组 2.1 检测是否为数组 2.2 增加数组长度导致未赋值的位置为undefined 2.3 用闭包实现简易迭代器 三. ...
- 《JavaScript面向对象编程指南(第2版)》读书笔记(二)
<JavaScript面向对象编程指南(第2版)>读书笔记(一) <JavaScript面向对象编程指南(第2版)>读书笔记(二) 目录 一.基本类型 1.1 字符串 1.2 ...
- 《JavaScript面向对象编程指南》读书笔记②
概述 <JavaScript面向对象编程指南>读书笔记① 这里只记录一下我看JavaScript面向对象编程指南记录下的一些东西.那些简单的知识我没有记录,我只记录几个容易遗漏的或者精彩的 ...
- 《JavaScript面向对象编程指南》读书笔记①
概述 JavaScript快忘完了,想看一本专业书拾遗,所以看了这本<JavaScript面向对象编程指南>. 个人觉得这本书讲的很透彻很易懂,一些原来有疑惑的地方在这本书里面豁然开朗,看 ...
- 「JavaScript面向对象编程指南」闭包
闭包 JS只有函数作用域,函数外为全局变量,函数内为局部变量 绿圆是函数fn的作用域,在这范围内可访问局部变量b和全局变量a,橙圆是fn内部函数inner的作用域,此范围内可访问自身作用域内的变量c, ...
- 《JavaScript面向对象编程指南》译者序
相对于Perl.Python等动态脚本语言来说,JavaScript确实是一门饱受误解的语言.对于译者这种从20世纪90年代末走过来的C++程序员来说,尤其如此.在那个年代,提起JavaScript总 ...
- 《JavaScript面向对象编程指南》
第一章.引言 1.5 面向对象的程序设计常用概念 对象(名词):是指"事物"在程序设计语言中的表现形式. 这里的事物可以是任何东西,我们可以看到它们具有某些明确特征,能执行某些动作 ...
- JavaScript面向对象编程指南
引言 面向对象程序设计 基本数据类型.数组.循环及条件表达式 基本数据类型 函数 函数Function 预定义函数 变量的作用域 函数也是数据 闭包 对象 原型 原型 继承 原型链 浅拷贝与深拷贝 原 ...
- [已读]JavaScript面向对象编程指南
又是一个忽悠人的书名,其实这本书的花了大量内容阐述JS的基础语法,BOM,DOM,事件,ajax(这个和很多js书一样).最后一章则是编程模式与设计模式. 我觉得与面向对象没多大关系,要算的话,pro ...
随机推荐
- 循环while 和 continue
while 1: print("行动吧") # 组成:while 条件: #条件为真,则执行语句块.之后再回去判断条件是否为真,再执行....till条件为假为止. 语句块 # 条 ...
- 【问题定位】tcpdump 抓包简易命令
tcpdump -A -i lo port 2003 or port 2103 or port 2203 | grep '.*system.*'
- 在WebStorm中使用CSScomb
在前端开发写CSS时,往往不能很好的把握格式和属性顺序,阅读起来不友好.CSScomb帮助我们解决了这个问题! CSScomb(CSS梳理)是一个可以用来格式化和排序CSS属性的插件,官网地址http ...
- 一劳永逸部署项目:通过tomcat加载环境变量
一劳永逸部署项目:通过tomcat加载环境变量 转载自:https://blog.csdn.net/u010414666/article/details/46499953 一.说明 项目中经常会用到x ...
- Python 3 实现定义跨模块的全局变量和使用
尽管某些书籍上总是说避免使用全局变量,但是在实际的需求不断变化中,往往定义一个全局变量是最可靠的方法,但是又必须要避免变量名覆盖. Python 中 global 关键字可以定义一个变量为全局变量,但 ...
- 【洛谷】【归并排序】P1908 逆序对
[题目描述:] 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是 ...
- 【openjudge】【递推】例3.4 昆虫繁殖
[题目描述] 科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强.每对成虫过x个月产y对卵,每对卵要过两个月长成成虫.假设每个成虫不死,第一个月只有一对成虫,且卵长成成虫后的第一个月不产卵 ...
- python matplotlib quiver——画箭头、风场
理解参考:https://blog.csdn.net/liuchengzimozigreat/article/details/84566650 以下实例 import numpy as np impo ...
- 1554: SG Value (巧妙的模拟题,也属于思维题)
1554: SG Value Submit Page Summary Time Limit: 5 Sec Memory Limit: 256 Mb Submitted: 4 ...
- K2使用Nginx做负载均衡
K2使用Nginx做负载均衡 K2目前是支持Load Balancing这种方式,来做负载均衡,也可以使用F5来做负载均衡,但这次我使用nginx来实现K2的负载均衡 下载nginx 请下载nginx ...