对于前端程序员来说闭包还是比较难以理解的,

闭包的形成与变量的作用域以及变量的生产周期密切相关,所以要先弄懂变量的作用域和生存周期。

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>

代码还是不难重在理解

  

最新文章

  1. 【linux】gcc命令
  2. 用edtftpj实现Java FTP客户端工具
  3. hdu 1031 (partial sort problem, nth_element, stable_partition, lambda expression) 分类: hdoj 2015-06-15 17:47 26人阅读 评论(0) 收藏
  4. Unity Shader播放序列帧动画
  5. Entity Framework6 访问MySQL
  6. CAF(C++ actor framework)使用随笔(使用类去构建actor和使用的一些思路)
  7. java IO选择流的原则及其与IO流相关类的关系
  8. JavaScript typeof, null, 和 undefined
  9. struts1:(Struts重构)构建一个简单的基于MVC模式的JavaWeb
  10. 001-JUnit之断言assert
  11. C# 微信网页授权多域名解决
  12. Django(十五)Form组件
  13. Jmeter 通过json Extracted 来获取 指定的值的id
  14. 【Selenium】selenium中隐藏元素如何定位?
  15. python-day73--django-用户验证
  16. 2018.11.06 洛谷P1941 飞扬的小鸟(背包)
  17. git status的用法
  18. Hadoop生态上几个技术的解释:hive、pig、hbase 关系与区别
  19. PHP代码优化—getter 和 setter
  20. 电脑开机svchost.exe报错

热门文章

  1. webpack 中导入 vue 和普通网页使用 vue 的区别(四)
  2. JavaScript 中的面向对象编程
  3. HDU4089(概率dp)
  4. [WOJ4354] 蜀石经
  5. 关于gc日志中Desired Survivor的疑问和对象晋升老年代的小结
  6. 109 Convert Sorted List to Binary Search Tree 有序链表转换二叉搜索树
  7. Spark Mllib里如何删除每一条数据中所有的双引号“”(图文详解)
  8. Aop第一节
  9. Java之内部类、包及代码块
  10. 杂谈 什么是伪共享(false sharing)?