《JavaScript设计模式与开发》笔记 4.闭包
- 1.变量的作用域
- 2.变量的生存周期
- 3.闭包更多作用
- 1.封装变量
- 2.延续局部变量寿命
- 4.闭包和面向对象设计
- 5.闭包和内存管理
1.变量的作用域
var func = function(){
var a = 1;
}
func();
console.log(a); //输出undefined
var a = 1;
fun1 = function(){
var b = 2;
fun2 = function(){
var c = 3;
console.log(b); //输出 2
console.log(a); //输出 1
}
fun2();
console.log(c); //输出undefined
}
fun1();
2.变量的生存周期
var func = function(){
var a = 1;
return function(){
a++;
console.log(a);
}
}
var f = func();
f(); // 输出1
f(); // 输出2
f(); // 输出3
f(); // 输出4
当退出函数后,局部变量a并没有消失,而是似乎一致在某个地方存活着。这是因为当执行var f = func();时,f返回了一个匿名函数的引用,它可以访问到func()被调用时产生的环境,而局部变量a一致处于这个环境里。既然局部变量所在的环境还能被外界,这个局部变量就有了不被销毁的理由。这里产生了一个闭包结构,局部变量的声明看起来被延续了。
既然f返回了一个匿名的函数引用,那么下面的也符合闭包
var func = (function(){
var a = 1;
return function(){
a++;
console.log(a);
}
})();
f(); // 输出1
f(); // 输出2
f(); // 输出3
f(); // 输出4
再次变种为引用对象的方式
var func = {
a :0,
call:function(){
this.a++;
console.log(this.a);
}
}
func.call(); //输出1
func.call(); //输出2
func.call(); //输出3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<script>
var nodes = document.getElementsByTagName('div');
for(var i =0;i<nodes.length;i++){
nodes[i].onclick=function(){
alert(i);
}
}
</script>
</body>
</html>
测试这段代码就会发现,无论点击哪个div,最后弹出的结构都是5,。这是因为div节点onclick事件是被异步出发的,当事件出发的时候,for循环早已结束,此时变量i的值已经是5,所以在div的onclick事件函数中顺着作用域链从内到外查找变量i时,查找到的值总是5。
解决方法是在闭包作用的帮助下,把每次循环的i值都封装起来。(就是把每个点击事件都独立放在内存里面。)
var nodes = document.getElementsByTagName('div');
for(var i =0;i<nodes.length;i++){
(function(i){
nodes[i].onclick=function(){
alert(i);
}
})(i);
}
3.闭包更多作用
1.封装变量
闭包可以帮组我们封装私有变量”
var mult = function(){
var a = 1;
for(var i =0;i <arguments.length;i++){
a = a*arguments[i];
}
return a;
}
console.log(mult(1,2,5));
mult函数接受一些number类型的函数,并返回这些参数的乘积。现在我们觉得对于这些那些参数来说,每次都进行计算是一种浪费,我们可以加入缓存机制来提高这个函数的性能。
var cache={};
var mult = function(){
var args = Array.prototype.join.call(arguments,','); //将参数对象变成一个字符串 args 1,2,3
if(cache[args]){
console.log('执行缓存');
return cache[args];
}
var a = 1;
for(var i=0;i<arguments.length;i++){
a = a*arguments[i];
}
return cache[args] = a;
}
console.log(mult(1,2,3)); //进行计算
console.log(mult(1,2,3)); //执行缓存,不用计算
继续封装减少页面全局变量
var mult = (function(){
var cache={}; //私有变量
return function(){
var args = Array.prototype.join.call(arguments,',');
if(cache[args]){
return cache[args];
}
var a = 1;
for(var i=0;i<arguments.length;i++){
a = a*arguments[i];
}
return cache[args] = a;
}
})()
console.log(mult(1,2,3)); //进行计算
console.log(mult(1,2,3)); //执行缓存,不用计算
提炼代码,独立模块
var mult = (function(){
var cache={}; //私有变量
var cala = function(){
var a = 1;
for(var i=0;i<arguments.length;i++){
a = a*arguments[i];
}
return a;
}
return function(){
var args = Array.prototype.join.call(arguments,',');
if(cache[args]){
return cache[args];
}
return cache[args] = cala.apply(null,arguments);
}
})();
console.log(mult(1,2,3)); //进行计算
console.log(mult(1,2,3)); //执行缓存,不用计算
2.延续局部变量的寿命
var report = function(src){
var img = new Image();
img.src = src;
}
利用闭包来延续img的使用
var report = (function(){
var imgs = []; //img就留在了内存里面
return function(src){
var img = new Image();
imgs.push(img);
img.src = src;
}
})();
4.闭包和面向对象
闭包:
var extent = function(){
var value =0;
return {
call:function(){
value++;
console.log(value);
}
}
}
var extent = extent();
extent.call(); //输出1
extent.call(); //输出2
extent.call(); //输出3
如果换成面向对象的写法就是
var extent = {
value :0,
call:function(){
this.value++;
console.log(this.value);
}
}
extent.call(); //输出1
extent.call(); //输出2
extent.call(); //输出3
5.闭包和内存管理
闭包是一个非常强大的特性,但人民对其他诸多误解,一种耸人听闻的说法就是闭包会造成内存泄漏。如果在将来需要回收这些变量,我们可以手动吧这些变量设置为null。
《JavaScript设计模式与开发》笔记 4.闭包的更多相关文章
- 《JavaScript设计模式与开发实践》读书笔记-基础知识
笔记内容多摘录自<JavaScript设计模式与开发实践>(曾探著),侵删. 面向对象的JavaScript 1. 动态需要类型和鸭子类型 鸭子类型 如果它走起路来像鸭子,叫起来也是鸭子, ...
- 《Javascript设计模式与开发实践》--读书笔记
第2章 this call apply bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用. bind( ...
- JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)
说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...
- 《JavaScript设计模式与开发实践》整理
最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...
- JavaScript设计模式与开发实践 - 单例模式
引言 本文摘自<JavaScript设计模式与开发实践> 在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返 ...
- 《javascript设计模式与开发实践》--- (单一职责原则)
看的这本书叫<JavaScript设计模式与开发实践> 先规划一下看书的顺序,基础知识我已经大概的浏览了一遍了,没有留下笔记,以后有时间还会补上.本来打算顺着看的.但是我感觉我很难短时间内 ...
- JavaScript设计模式与开发实践 - 观察者模式
概述 观察者模式又叫发布 - 订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个目标对象(为了方便理解,以下将观察者对象叫做订阅者,将目标对象叫做 ...
- JavaScript设计模式与开发实践 - 策略模式
引言 本文摘自<JavaScript设计模式与开发实践> 在现实中,很多时候也有多种途径到达同一个目的地.比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路. 如果没有时间但 ...
- 《JavaScript设计模式》读书笔记——灵活的语言
最近在读JavaScript设计模式这本书,准备搞一个系列来记录所学所想,其实主要原因是方便以后查阅. 第一章主要介绍了JS函数的不同定义与使用方法,用自己的方法去模拟类也是它的独有魅力所在. 首先, ...
- 《javascript设计模式与开发实践》读书笔记之函数,this,闭包
一.函数基本理论 function compare(val1,val2){ return val1 - val2; }var result = compare(5,10); 1,函数的定义没什么意义, ...
随机推荐
- python3.6升级
Ubuntu 14.04 and 16.04 If you are using Ubuntu 14.04 or 16.04, you can use Felix Krull's deadsnakes ...
- opengl学习,一篇就够你基本了解
http://blog.csdn.net/iduosi/article/details/7835624
- Deinstall卸载RAC之Oracle软件及数据库+GI集群软件
Deinstall卸载Oracle软件及数据库+GI集群软件 1. 本篇文档应用场景: 需要安装新的ORACLE RAC产品,系统没有重装,需要对原环境中的RAC进行卸载: #本篇文档,在AIX 6. ...
- 双向重定向tee命令详解
vim一般在训练网络的时候需要保存log文件,同时需要在屏幕上网络的输出信息,在shell文件中常常会看到如下代码 执行的命令 2>&1 | tee log.txt tee是linux中 ...
- JAVA基础部分复习(二、集合类型)
对于这些常用的集合,建议还是需要先了解一下底层实现原理,这样在不同的使用场景下才能选择更好的方案. Set介绍以及对比,常用方法: package cn.review.day02; import ja ...
- EF数据库配置
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSec ...
- [LeetCode&Python] Problem 860. Lemonade Change
At a lemonade stand, each lemonade costs $5. Customers are standing in a queue to buy from you, and ...
- Unity导航系统Navigation使用教程
Unity开发VR之Vuforia 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...
- 图片上传并回显Ajax异步篇
图片上传并回显Ajax异步篇 图片如何无刷新的上传到服务器呢?继前两篇文章后,我们来实战一下如何无刷新的异步上传图片,我们还是先看一下效果 在实战前呢,我们需要做些准备工作.比如说,了解一下FormD ...
- Github&&SourceTree
如何将本地的代码或者是文件上传到github 方法一:(github上面创建仓库,远程仓库克隆到本地,将文件拖拽到本地仓库) cd 文件夹 git clone 链接(github上面创建新仓库的链 ...