JavaScript设计模式基础之闭包(终)
对于前端程序员来说闭包还是比较难以理解的,
闭包的形成与变量的作用域以及变量的生产周期密切相关,所以要先弄懂变量的作用域和生存周期。
1.变量作用域
变量的作用域,就是指变量的有效范围,通常我们指的作用域就是函数作用域(毕竟全局的作用域没有要指的意义,关键哪都能访问)
声明变量的时候推荐使用es6语法中的let 和const 可以避免var声明变量出现的一些不必要的错误而且let声明变量只作用于当前作用域 避免使用不带var 或者let直接声明变量,可能会导致命名冲突。
2.变量生存周期
除了变量作用域之外,另外一个跟闭包有关的概念就是变量生存周期。
对于全局变量来说,它的生存周期就是永久,除非我们主动销毁它,而对于函数里面声明的变量来说 它的生存周期会随着函数调用解释而被销毁。
闭包的定义: 最简单直白的说法就是 函数返回函数
闭包的应用:封装私有变量、延续局部变量的寿命
1.封装私有变量:
使用闭包可以把一些不需要暴露在全局的变量封装成“私有变量”
如有一个计算数组偶数乘积的方法:
let num = function(arr){
let a = 1;
for(let i = 0; i < arr.length; i++){
if(arr[i] % 2 === 0){
a *= arr[i];
}
}
return a;
}
console.log( num([1,2,3,4]));//输出8
加入缓存机制提高函数性能:
let cache = {};
let num = function(arr){
let args = Array.prototype.join.call(arr,',');//输出1,2,3,4
console.log(cache[args])//第一次调用输出为undefined进行下一步计算 第二次调用输出8 直接返回
//传入相同参数就比不必进行计算 直接返回缓存提高性能
if(cache[args]){
return cache[args];
}
//不是相同参数则进行计算
let a = 1;
for(let i = 0; i < arr.length; i++){
if(arr[i] % 2 === 0){
a *= arr[i];
}
}
return cache[args] = a;
}
console.log( num([1,2,3,4]));//8 进行计算
console.log( num([1,2,3,4]));//8 返回缓存
这明显能看到cache这个缓存变量只在num函数里面被使用,与其让它们一起暴露在全局不然把它封装在num函数内部,减少页面中的全局变量,以免该变量在其他地方被修改而引发错误
封装后代码如下:
let num = (function(){
let cache = {};
return function(arr){
let args = Array.prototype.join.call(arr,',');//输出1,2,3,4
console.log(cache[args])//第一次调用输出为undefined进行下一步计算 第二次调用输出8 直接返回
//传入相同参数就比不必进行计算 直接返回缓存提高性能
//判断cache缓存对象里面有args这个key值没
if(args in cache){
return cache[args];
}
//不是相同参数则进行计算
let a = 1;
for(let i = 0; i < arr.length; i++){
if(arr[i] % 2 === 0){
a *= arr[i];
}
}
return cache[args] = a;
}
})();
console.log( num([1,2,3,4]));//8 进行计算
console.log( num([1,2,3,4]));//8 返回缓存
2.延续局部变量寿命
src属性会自动请求服务器数据如下
let report = function(src){
let img = new Image();
img.src = src;
console.log(img.src);
}
report(`https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537779456907&di=c72dd79d1dbb02bb9340743bf08e99f7&imgtype=0&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F94cad1c8a786c91723e93522c43d70cf3ac757c6.jpg`);
但是一些低版本的浏览器实现存在着bug,在这些浏览器上面使用该函数会丢失数据 因为函数调用结束后变量销毁 我们可以用闭包封闭起来就能解决低版本浏览器bug
代码如下:
let report = (function(){
let imgs = [];
return function(src){
let img = new Image();
imgs.push(img);
img.src = src;
}
})()
report(`https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537779456907&di=c72dd79d1dbb02bb9340743bf08e99f7&imgtype=0&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F94cad1c8a786c91723e93522c43d70cf3ac757c6.jpg`);
接下来要来点干货了
用闭包实现命令模式:
在JavaScript中闭包的各种设计模式实现里面,闭包的运用特别广泛,在我后续的博客中将体会到这一点
简单编写一段闭包实现命令模式 如果上述的闭包使用你基本会了的话不会对我们的理解造成困难
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="start">打开电脑</button>
<button id="end">关闭电脑</button>
<script>
//命令
let Computer = {
open(){
alert('打开电脑');
},
close(){
alert('关闭电脑');
}
}
//创建命令执行中介
let createCommand = function(receiver){
//执行
let execute = function(){
return receiver.open();
}
//关闭
let undo = function(){
return receiver.close();
}
return {
execute,
undo
}
};
//设置执行命令者
let setCommand = function(command){
document.querySelector('#start').onclick = function(){
command.execute();//输出打开电脑
}
document.querySelector('#end').onclick = function(){
command.undo();//输出关闭电脑
}
}
//传入命令方法 传入执行中介
setCommand(createCommand(Computer));
</script>
</body>
</html>
代码还是不难重在理解
JavaScript设计模式基础之闭包(终)的更多相关文章
- JavaScript设计模式基础(二)
JavaScript 设计模式基础(一) 原型模式 在以类为中心的面向对象编程语言中,类和对象的关系就像铸模和铸件的关系,对象总是从类中创建.而原型编程中,类不是必须的,对象未必从类中创建而来,可以拷 ...
- JavaScript设计模式基础(一)
模式的起源 模式 起源于建筑学.20世纪70年代,哈佛大学建筑学博士Christopher Alexander和他的团队花大约20年,来研究为解决同一个问题而设计出的不同建筑结构,从中发现那些高质量设 ...
- JavaScript设计模式基础之面向对象的JavaScript(一)
动态语言类型与鸭子类型 此内容取自JavaScript设计模式与开发实践一书 编程语言按照数据类型大体可以分为2类,一类就是静态类型语言,另一类则是动态类型语言 静态类型语言也可以称之为编译语言,而动 ...
- JavaScript设计模式基础之this、call、apply
1.this的指向 除去不常用的with和eval,具体应用中this指向大概能分为4种情况分别是 1.作为对象的方法调用. 2.作为普通函数的方法调用. 3.Function.prototype.c ...
- javascript设计模式学习之三—闭包和高阶函数
一.闭包 闭包某种程度上就是函数的内部函数,可以引用外部函数的局部变量.当外部函数退出后,如果内部函数依旧能被访问到,那么内部函数所引用的外部函数的局部变量就也没有消失,该局部变量的生存周期就被延续. ...
- JavaScript设计模式基础之面向对象的JavaScript(二)
多态 多态的实际含义:同一操作作用与不同的对象上面,可以产生不同的解释和不同的执行结果,就是说,给不同的对象发送同一个消息 的时候,这些对象会根据这个消息分别给出不同的反馈 代码如下: class D ...
- 《JavaScript设计模式与开发实践》读书笔记-基础知识
笔记内容多摘录自<JavaScript设计模式与开发实践>(曾探著),侵删. 面向对象的JavaScript 1. 动态需要类型和鸭子类型 鸭子类型 如果它走起路来像鸭子,叫起来也是鸭子, ...
- 转载,javascript 设计模式
了解JavaScript设计模式我们需要知道的一些必要知识点:(内容相对基础,高手请跳过) 闭包:关于闭包这个月在园子里有几篇不错的分享了,在这我也从最实际的地方出发,说说我的理解. 1.闭包最常用的 ...
- 【JavaScript设计模式系列---开篇预览】
转:http://www.cnblogs.com/Darren_code/archive/2011/08/31/JavascripDesignPatterns.html 2011-08-31 23:5 ...
随机推荐
- Rsync备份同步数据工具
Rsync is a fast and extraordinarily versatile file copying tool. Rsync是一款开源的,快速的,多功能的,可实现全量和增量的本地 ...
- 可以提升3倍开发效率的 Intellij IDEA快捷键大全汇总(2019)
整理了一下IDEA的常用快捷键,可以打印出来或者弄成图片设置为桌面,为广大的程序员们节省更多的时间去谈恋爱. 常用快捷键1 Ctrl+Shift + Enter,语句完成 “!”,否定完成,输入表达式 ...
- Git,SVN的优缺点及适合的范围,开源项目?公司项目?
Git,SVN的优缺点及适合的范围,开源项目?公司项目? 使用git不久,粗浅理解: 1)适用对象不同.Git适用于参与开源项目的开发者.他们由于水平高,更在乎的是效率而不是易用性.Svn则不同,它适 ...
- DHCP snooping(DHCP监听)
DHCP监听可以防范利用DHCP发起的多种攻击行为,如DHCP中间人攻击,伪造多台设备耗尽地址池 DHCP监听允许可信端口上的所有DHCP消息,但是却过滤非可信端口上的DHCP消息,DHCP监听还会在 ...
- HDU6299(2018多校第一场)
Bryce1010模板 http://acm.hdu.edu.cn/showproblem.php?pid=6299 两个字符串的排序可以分成四种情况: (1)str1左少右多 vs str2 左多右 ...
- vue.js 中如何解除绑定事件
我们项目中有一个点赞需求,只允许点击一次赞,再次点击则取消赞, 为了防止用户多次连续点击,在点赞后需要解绑事件,成功调取API后,才可再次点击取消赞. 目前用的方法是加入一个flag控制点击事件可否点 ...
- 092 Reverse Linked List II 反转链表 II
反转从位置 m 到 n 的链表.用一次遍历在原地完成反转.例如:给定 1->2->3->4->5->NULL, m = 2 和 n = 4,返回 1->4-> ...
- [转]Formatting the detail section to display multiple columns (水晶报表 rpt 一页多列)
本文转自:http://www.bofocus.com/formatting-the-detail-section-to-display-multiple-columns/ Format the de ...
- SQL server事务语法
ALTER proc [dbo].[p_BOGetMCBSecurityCheckPropertiesTypeAdd]@Name nvarchar(50), ---参数@MCBBadlyBuil ...
- JS排序--快速排序
用 JavaScript 实现快速排序代码如下: /* * @author liphong * @data 2019/02/24 */ var arr = []; // 需要被排序数组 /* * 分离 ...