「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"> /*函数的声明组成: ...
随机推荐
- Scala--控制结构和函数
一.条件表达式 val s = if(x > 1) 1 else -1 s 可以是 val var s = 0 if(x > 1) s = 1 else s = -1 s 必须是 var ...
- Java SpringBoot集成RabbitMq实战和总结
目录 交换器.队列.绑定的声明 关于消息序列化 同一个队列多消费类型 注解将消息和消息头注入消费者方法 关于消费者确认 关于发送者确认模式 消费消息.死信队列和RetryTemplate RPC模式的 ...
- bound+vlan
- centos7重置root密码
修改centos7的root密码重置非常简单,只需要登录系统,执行passwd按enter即可, 但是如果忘记root密码,该如何修改呢 1, 重启系统之后,系统启动进入欢迎界面,加载内核步骤时,选中 ...
- jquery中关键字写错导致的错误——dataType写成dateType(data写成date)
由于不会报错,会导致原本servlet后端传回的json字符串不能被正确解析为json格式,而只是显示为字符串. 具体错误表现为:在浏览器Console中显示为字符串,但是在json.cn中可以被正常 ...
- Asp.Net Core配置的知识总结
配置在Asp.Net Core中由四个核心的对象组成: IConfiguration:配置的最终产出物,它代表了整个asp.net core应用的配置树,这棵树有根节点,子节点和叶子节点,根节点由IC ...
- jsonp原理,封装,应用(vue项目)
jsonp原理 JSON是一种轻量级的数据传输格式. JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题.由于同源策略,一般来说位于 ...
- 多线程threading
threading用于提供线程相关的操作,线程是应用程序中工作的最小单元.python当前版本的多线程库没有实现优先级.线程组,线程也不能被停止.暂停.恢复.中断. 1. threading模 ...
- 简单实现SSO
方案一:原理:基于SSO Server 端的登录情况,跳转至SOO-client的各个端. 每次返回一个 ticker 随机票据值识别. 配置服务端 执行 :git clone https://git ...
- python10--函数的来源,优点,定义,组成,使用(定义,调用)函数的分类,函数的返回值
一.函数 # *****# 函数:完成 特定 功能的代码块,作为一个整体,对其进行特定的命名,该名字就代表函数# -- 现实中:很多问题要通过一些工具进行处理 => 可以将工具提前生产出 ...