「JavaScript面向对象编程指南」闭包
闭包

JS只有函数作用域,函数外为全局变量,函数内为局部变量
绿圆是函数fn的作用域,在这范围内可访问局部变量b和全局变量a,橙圆是fn内部函数inner的作用域,此范围内可访问自身作用域内的变量c,也可访问父级作用域的变量b,这就形成了一条作用域链
全局空间(蓝圆)为0级作用域,绿圆是1级作用域,橙圆为2级作用域,依次类推
橙圈可访问绿圈或蓝圈内的数据,但蓝圈内访问不了绿圈,绿圈访问不了橙圈,也就是可以一路由内向外访问,但由外到内却不行
若把橙圈拿到绿圈外,蓝圈内的位置,就形成了闭包

现在橙圈也就是函数inner和变量a一样,都是在全局作用域中,并且inner还记得它被定义时所设定的环境,因此它依旧可访问绿圈也就是函数fn的作用域并使用变量b
突破作用域链的途径,升级为全局变量 或 传递(返回)给全局作用域即可
闭包#1
var a = 'global var';
var fn = function () {
var b = 'local var';
var inner = function () {
var c = 'inner';
return b;
}
return inner;
}
var f2 = fn(); //或者直接fn()();
f2();
函数fn中返回了inner,而inner内返回的变量b,现在inner和b都可通过作用域链进行访问
闭包#2
var f2; //函数占位符,这不是必须的,但最好写上
var fn = function () {
var b = 'local var';
var inner = function () {
var c = 'inner';
return b;
}
f2 = inner;
}
fn();
f2();
将函数inner在fn内赋值给全局变量f2,由于inner是在fn内定义的,所以即使该函数后来升级成了全局函数,也依然保留着对fn作用域的访问权
闭包#3
function fn(param) {
var inner = function () {
return param;
}
param++;
return inner;
}
var f2 = fn(123);
f2();
返回函数被调用时,param++已执行一次,所以f2()结果是124
由此可见,函数绑定的是作用域本身,而不是函数定义时该作用域中的变量或变量当前返回的值
闭包#4循环中的闭包
依次输出0,1,2
function fn() {
var arr = [],i;
for(i = 0; i < 3; i++){
arr[i] = function () {
return i;
}
}
return arr;
}
var arr2 = fn();
> arr2[0](); //3 , >表示在控制台输入
> arr2[1](); //3
> arr2[2](); //3
这里创建了三个闭包,都指向一个共同的局部变量i,但闭包不会记录它们的值,它们拥有的只是相关域在创建时的一个引用
对这三个函数任一个而言,当它去获取某个变量时,会从其所在的域开始逐级寻找那个距离最近的i值。由于循环结束时i为3,所以这三个函数都指向了这一共同值
若想输出的是0,1,2,则需要换种闭包形式
function fn() {
var arr = [],i;
for(i = 0; i < 3; i++){
arr[i] = (function (x) {
return function () {
return x;
};
}(i));
}
return arr;
}
var arr2 = fn();
> arr2[0](); //0
> arr2[1](); //1
> arr2[2](); //2
这里不再直接创建一个返回i的函数,而是将i传递给另一个自调用函数,在该函数中
i被赋值给了局部变量x,这样一来,每次迭代中i的值就能保存在局部变量x中
也可以使用函数声明的方式
function fn() {
var arr = [],i;
for(i = 0; i < 3; i++){
arr[i] = binder(i);
}
return arr;
function binder(x) {
return function () {
return x;
}
}
}
var arr2 = fn();
arr2[0](); //0
arr2[1](); //1
arr2[2](); //2
闭包#5
假设有个变量,表示的是某类特定值,不想将其暴露给外部,因为那样的话其他部分的代码就可能直接修改它,所以需要将其保护在相关函数内部,然后提供getter和setter函数用以访问和设置该变量的值
var getValue,setValue;
(function () {
var secret = 0;
getValue = function(){
return secret;
};
setValue = function(v){
if(typeof v === 'number'){ //假设这里有验证措施
secret = v;
}
};
}())
> getValue(); //0
> setValue(123);
> getValue(); //123
将getter和setter函数放在一个共同的函数中,并在该函数中定义secret变量,使这两函数能共享同一作用域
通过一个自调用函数,在其中定义了全局函数setValue和getValue函数,并以此确保局部变量secret的不可直接访问性
闭包#6迭代器
有时会面对复杂的数据结构,它们通常有着与数组截然不同的序列规则,此时就需要将一些“谁是下一个”的复杂逻辑封装成易于使用的next()函数,然后只需简单地调用next()就能实现相关的遍历操作
function setup(x) {
var i = 0;
return function () {
return x[i++];
}
}
var next = setup(['a','b','c']);
> next(); // “a”
> next(); // "b"
在setup()函数中定义一个私有指针i,该指针会始终指向数组的下一个元素
「JavaScript面向对象编程指南」闭包的更多相关文章
- 「JavaScript面向对象编程指南」对象
对象的属性名可加上引号,下面三行代码所定义的内容是完全相同的 var hero = { occupation : 1 }; var hero = { "occupation" : ...
- 「JavaScript面向对象编程指南」基础
DOM标准是独立的(即并不依赖JS)操作结构化文档的方式 BOM实际是个与浏览器有关的对象集合,原来没任何标准可言,H5诞生后才被定义了一些浏览器间通用的对象标准 ES5严格模式"use s ...
- 「JavaScript面向对象编程指南」原型
在 JS 中,函数本身也是一个包含了方法(如apply和call)和属性(如length和constructor)的对象,而prototype也是函数对象的一个属性 function f(){} f. ...
- 闭包初体验 -《JavaScript面向对象编程指南》
下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 参考<JavaScript面向对象编程指南> 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函 ...
- 《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面向对象编程指南(三) 函数
第3章 函数 3.1 什么是函数 函数:本质是一种代码的分组形式.函数的声明如下: <script type="text/javascript"> /*函数的声明组成: ...
随机推荐
- EntityFramework 6.x和EntityFramework Core必须需要MultipleActiveResultSets?
前言 本节我们来探讨到底需不需要在连接字符串上加上MultipleActiveResultSets = true ?,若您有更深层次的理解欢迎留下您的脚印. EntityFramework 6.x和E ...
- html与ios交互方法 WebViewJavascriptBridge
WebViewJavascriptBridge 1.html调用ios的方法 <!DOCTYPE html> <html lang="en"> <he ...
- Carthage下没有Build文件夹
问题描述: 用Carthage管理项目时,执行Carthage upate --platform iOS后发现Carthage目录下没有Build文件夹 解决方案: 在Xcode > Prefe ...
- Photoshop给人像加上个性裂纹肌肤
1.打开人物及纹理素材图片,把素材图片拖到人物图片里面,适当降低图层不透明度. 2.选择菜单:编辑 > 变形 > 自由变形,使纹理位置合适,然后确定. 3.用橡皮工具擦除多余的地方. 4. ...
- 暂时禁止Cnario Player开机自动启动的办法
如果暂时不需要播放器开机后启动Cnario Player, 有两种办法 从Windows启动菜单禁用Cnario Player 在Windows的任务管理器中, 找到启动标签栏, 从里面找到Cnari ...
- Flutter之内置动画(转)
AnimatedContainerAnimatedCrossFadeHeroAnimatedBuilderDecoratedBoxTransitionFadeTransitionPositionedT ...
- 洛谷P1122最大子树和题解
题目 一道比较好想的树形\(DP\) 完全可以用树形DP的基本思路,递归,然后取最优的方法. \(Code\) #include <iostream> #include <cstri ...
- HTML&CSS_基础01
一.预备知识: # 1. HTML5 是 W3C 与 WHATWG 合作的结果. W3C 指 World Wide Web Consortium,万维网联盟. WHATWG 指 Web H ...
- 不转实体直接获取Json字符串中某个字段的值
JObject jo = (JObject)JsonConvert.DeserializeObject(JsonStr);//JsonStr 为Json字符串 string lng = jo[&quo ...
- 洛谷P5155 [USACO18DEC]Balance Beam(期望,凸包)
你以为它是一个期望dp,其实它是一个凸包哒! 设平衡木长度为\(L\),把向右走平衡木那个式子写一下: \[dp[i]=\frac{dp[i+1]+dp[i-1]}{2}\] 然后会发现这是一个等差数 ...