前面的话

  根据闭包的定义,我们知道,无论通过何种手段,只要将内部函数传递到所在的词法作用域以外,它都会持有对原始作用域的引用,无论在何处执行这个函数都会使用闭包。接下来,本文将详细介绍闭包的10种形式

返回值

  最常用的一种形式是函数作为返回值被返回

var F = function(){
var b = 'local';
var N = function(){
return b;
}
return N;
}
console.log(F()());

函数赋值

  一种变形的形式是将内部函数赋值给一个外部变量

var inner;
var F = function(){
var b = 'local';
var N = function(){
return b;
};
inner = N;
};
F();
console.log(inner());

函数参数

  闭包可以通过函数参数传递函数的形式来实现

var Inner = function(fn){
console.log(fn());
}
var F = function(){
var b = 'local';
var N = function(){
return b;
}
Inner(N);
}
F();

IIFE

  由前面的示例代码可知,函数F()都是在声明后立即被调用,因此可以使用IIFE来替代。但是,要注意的是,这里的Inner()只能使用函数声明语句的形式,而不能使用函数表达式。详细原因移步至此

function Inner(fn){
console.log(fn());
}
(function(){
var b = 'local';
var N = function(){
return b;
}
Inner(N);
})();

循环赋值

  在闭包问题上,最常见的一个错误就是循环赋值的错误。关于其错误原因的详细解释移步至此

function foo(){
var arr = [];
for(var i = 0; i < 2; i  ){
arr[i] = function(){
return i;
}
}
return arr;
}
var bar = foo();
console.log(bar[0]());//2    

  正确的写法如下

function foo(){
var arr = [];
for(var i = 0; i < 2; i  ){
arr[i] = (function fn(j){
return function test(){
return j;
}
})(i);
}
return arr;
}
var bar = foo();
console.log(bar[0]());//0    

g(s)etter

  我们通过提供getter()和setter()函数来将要操作的变量保存在函数内部,防止其暴露在外部

var getValue,setValue;
(function(){
var secret = 0;
getValue = function(){
return secret;
}
setValue = function(v){
if(typeof v === 'number'){
secret = v;
}
}
})();
console.log(getValue());//0
setValue(1);
console.log(getValue());//1

迭代器

  我们经常使用闭包来实现一个累加器

var add = (function(){
var counter = 0;
return function(){
return   counter;
}
})();
console.log(add())//1
console.log(add())//2  

  类似地,使用闭包可以很方便的实现一个迭代器

function setup(x){
var i = 0;
return function(){
return x[i  ];
}
}
var next = setup(['a','b','c']);
console.log(next());//'a'
console.log(next());//'b'
console.log(next());//'c'

区分首次

var firstLoad = (function(){
var _list = [];
return function(id){
if(_list.indexOf(id) >= 0){
return false;
}else{
_list.push(id);
return true;
}
}
})();
firstLoad(10);//true
firstLoad(10);//false
firstLoad(20);//true
firstLoad(20);//false

缓存机制

  通过闭包加入缓存机制,使得相同的参数不用重复计算,来提高函数的性能

  未加入缓存机制前的代码如下

var mult = function(){
var a = 1;
for(var i = 0,len = arguments.length; i<len; i  ){
a = a * arguments[i];
}
return a;
}

  加入缓存机制后,代码如下

var mult = function(){
var cache = {};
var calculate = function(){
var a = 1;
for(var i = 0,len = arguments.length; i<len; i  ){
a = a * arguments[i];
}
return a;
};
return function(){
var args = Array.prototype.join.call(arguments,',');
if(args in cache){
return cache[args];
}
return cache[args] = calculate.apply(null,arguments);
}
}()

img对象

  img对象经常用于数据上报

var report = function(src){
var img = new Image();
img.src = src;
}
report('http://xx.com/getUserInfo');

  但是,在一些低版本浏览器中,使用report函数进行数据上报会丢失30%左右的数据,也就是说,report函数并不是每一次都成功地发起了HTTP请求

  原因是img是report函数中的局部变量,当report函数的调用结束后,img局部变量随即被销毁,而此时或许还没来得及发出HTTP请求,所以此次请求就会丢失掉

  现在把img变量用闭包封闭起来,就能解决请求丢失的问题

var report = (function(){
var imgs = [];
return function(src){
var img = new Image();
imgs.push(img);
img.src = src;
}
})()
report('http://xx.com/getUserInfo');

更多专业前端知识,请上 【猿2048】www.mk2048.com

深入理解闭包系列第五篇——闭包的10种形式相关推荐

  1. 深入理解ajax系列第五篇——进度事件

    前面的话 一般地,使用readystatechange事件探测HTTP请求的完成.XHR2规范草案定义了进度事件Progress Events规范,XMLHttpRequest对象在请求的不同阶段触发 ...

  2. 互联网神经学系列第五篇:研究大脑中的谷歌,脸书和华为思科路由,脑互联网生理学

    本文是互联网神经学系列第五篇-"大脑中的类互联网应用和结构,脑互联网生理学" 一.人类大脑研究的困境 大脑的秘密一直是科学皇冠上最明亮的宝石之一,但在两千年前,人们确连它的重要意义 ...

  3. 【云原生Kubernetes系列第五篇】kubeadm v1.20 部署K8S 集群架构(人生这道选择题,总会有遗憾)

    系列文章目录 ??即日起,更新云原生相关知识,喜欢的小伙伴可以给我点个三连喔 ??收录至专栏 云原生 ??[云原生Docker系列第一篇]Docker镜像管理 ??[云原生Docker系列第二篇]Do ...

  4. 转载 解密蓝牙mesh系列 | 第五篇 【好友(Friend)和低功耗节点(LPN)】【友谊(Friendship)参数】【友谊建立】【友谊(Friendship)消息传送】【安全性】【友谊终止】

    YD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机.32位ARM Cortex-M0处理器.128kB Flash存储器.以及丰富的数字接口.SYD8801片上集成了B ...

  5. requests 获取div_爬虫系列第五篇 使用requests与BeautifulSoup爬取豆瓣图书Top250

    上一篇我们学习了BeautifulSoup的基本用法,本节我们使用它来爬取豆瓣图书Top250. 一.网页分析 我们爬取的网页的url是https://book.douban.com/top250?i ...

  6. Python金融系列第五篇:多元线性回归和残差分析

    作者:chen_h 微信号 & QQ:862251340 微信公众号:coderpai 第一篇:计算股票回报率,均值和方差 第二篇:简单线性回归 第三篇:随机变量和分布 第四篇:置信区间和假设 ...

  7. HPM6750系列--第五篇 使用Segger Embedded Studio for RISC-V开发环境

    一.目的 之前的博文中<HPM6750系列--第四篇 搭建Visual Studio Code开发调试环境>我们介绍了如何使用visual studio code进行开发调试,但是用起来总 ...

  8. 博客推荐系列第五篇:PPT高手推荐-秋叶、萧秋水、孙小小等

    我们每天都在跟PPT打交道,但很多时候,发现写好PPT的人非常非常少,在所有我见过写PPT的人中,有5%已经非常不错了. 本人一直以为在所在的团队写的售前方案,演示PPT还是不错的,可是,自从我看到秋 ...

  9. 深入理解脚本化CSS系列第五篇——动态样式

    前面的话 很多时候,DOM操作比较简单明了,因此用javascript生成那些通常原本是HTML代码生成的内容并不麻烦.但由于浏览器充斥着隐藏的陷阱和不兼容问题,处理DOM中的某些部分时要复杂一些,比 ...

最新文章

  1. IE不能开新窗口的解决方法
  2. 成绩查看_托福网考免费寄送成绩单,掌握这些知识能帮你省不少钱!
  3. java-1.11.0的环境配置,JAVA 环境配置
  4. MATLAB 数据分析方法(第2版)1.3 MATLAB基本语法
  5. 京东10亿级调用量背后的高可用网关系统架构实践!
  6. 在windows中手动安装第三方模块
  7. LeetCode 1305. 两棵二叉搜索树中的所有元素(二叉树迭代器)
  8. div和div之间画横线_javascript – jQuery – 使用画布在div之间绘制线条
  9. html5 多文件选择
  10. c语言源程序最多可能由组成,一个c语言源程序是由什么组成_后端开发
  11. NRF24L01调试的一些经验之谈
  12. 怎么打开linux的超级终端,电脑超级终端在哪里|电脑打开超级终端的方法
  13. WPS页眉不同页之间的修改
  14. 无法通过计算机名访问 win10,win10系统主机名无法访问局域网共享的恢复方法
  15. Magica Cloth服装模拟插件分享
  16. 前端工程师的三种级别,技术决定你能拿5K,还是15K,还是25K
  17. ubuntu-16.04.6安装教程
  18. Error: C9555E: License checkout for feature LIC0=KA...-.....-..... with version 5.0201503 has been
  19. 企业微博营销平台营销模式是怎样的?
  20. 淘宝/天猫开放平台新商品发布API接口,商品发布接口,店铺上传接口,利用淘宝新品发布商品接口进行上传商品至淘宝店铺,接口对接方案

热门文章

  1. vue v html安全,vue 中控制v-html 中的样式,但不影响全局的小技巧
  2. 【OFDM系列2】OFDM复信号符号信噪比EsN0、比特信噪比EbN0、SNR的含义及关系详解
  3. comsol分析时总位移代表什么_超弹性材料模型的压缩分析
  4. java描边_shape描边设置是否显示四周描边
  5. python调用mysql数据库sql语句过长有问题吗_python操作mysql数据库,一次性执行多条语句不执行...
  6. 循环语句 for循环、while循环、do while循环
  7. Alias Method解决随机类型概率问题(别名算法)
  8. $(document).ready() 和 window.onload 方法比较
  9. Windows 8.1 新增控件之 Hyperlink
  10. 实现flash的图片切换效果【可以切换多个网页或者图片】