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

前面的话

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

selenium 常见问题

启动selenium时报错如下异常&#xff1a; selenium.common.exceptions.WebDriverException: Message: geckodriver executable needs to be in PATH. 解决方式&#xff1a;需要下载geckodriver&#xff0c;并放在path的环境变量下&#xff0c;下载地址&#xff1a;https://gith…

通过示例了解挥发

我们已经花了几个月的时间来稳定Plumbr中的锁定检测功能 。 在此期间&#xff0c;我们遇到了许多棘手的并发问题。 许多问题是独特的&#xff0c;但是一种特殊类型的问题一直反复出现。 您可能已经猜到了–滥用volatile关键字。 我们已经发现并解决了许多问题&#xff0c;其中…

jQuery设计思想

前面的话 在深入了解jQuery的各个细节之前&#xff0c;需要对jQuery的设计思想有一个大致的了解。在遇到问题时&#xff0c; 知道应该使用jQuery的哪一个功能&#xff0c;然后迅速从手册中找到具体的用法。本文将详细介绍jQuery的设计思想 选择元素 jQuery的基本设计思想和主要…

sql性能优化二

1、IN 操作符 用IN写出来的SQL的优点是比较容易写及清晰易懂&#xff0c;这比较适合现代软件开发的风格。但是用IN的SQL性能总是比较低的&#xff0c;从Oracle执行的步骤来分析用IN的SQL与不用IN的SQL有以下区别&#xff1a; ORACLE试图将其转换成多个表的连接&#xff0c;如果…

cf1039D 分块

cf1039D 链接 cf 思路 一次k可以贪心O(n)算。 对于\(≤\sqrt{n}\)的k&#xff0c;暴力算。 对于\(&#xff1e;\sqrt{n}\)的k&#xff0c;最多会有\(\sqrt{n}\)种答案&#xff0c;而且答案单调。 二分就行了。 复杂度\(O(nlognn\sqrt{n}logn)\) 递归会被卡&#xff0c;所以要记…

Source Insight 常用设置和快捷键大全

摘自&#xff1a;https://www.cnblogs.com/bluestorm/archive/2012/10/28/2743792.html Source Insight 4.0 文件类型、编码格式、tab转空格、tab键自动补全设置。。。http://www.cnblogs.com/bluestorm/p/6864540.html 1.括号配对高亮&#xff1a;“在前括号左侧&#xff0c;后…

JUnit中的参数化测试运行器

我们都有书面的单元测试&#xff0c;其中在一个测试中针对不同的可能的输入输出组合进行测试。 让我们以一个简单的斐波那契数列为例来看看它是如何完成的。 以下代码针对提到的元素数量计算斐波那契数列&#xff1a; import java.math.BigInteger; import java.util.ArrayLi…

HDU 1212 Big Number

题意&#xff1a;给一数字字符串s ( ns.size()<1000 ) 和数字m (<1e5) 求s%m 模拟除法&#xff0c; k初值0&#xff0c;按s[0]...累乘相加&#xff0c;把字符串还原成数字&#xff0c;比m大时-m&#xff0c;继续按位还原到s[n-1] 此时剩下的k再%m即为所求 #include<…

BOM之navigator对象和用户代理检测

前面的话 navigator对象现在已经成为识别客户端浏览器的事实标准&#xff0c;navigator对象是所有支持javascript的浏览器所共有的。本文将详细介绍navigator对象和用户代理检测 属性 与其他BOM对象的情况一样&#xff0c;每个浏览器中的navigator对象也都有一套自己的属性。下…

CF888G XOR-MST 最小异或生成树

CF888G XOR-MST 链接 CF888G 思路 trie上贪心&#xff0c;先左右两边连边&#xff0c;再用一条边的代价连起左右两颗树。因为内部的边一定比跨两棵树的边权笑&#xff0c;显然是对的。 代码自己瞎yy的。启发式合并 代码 #include <bits/stdc.h> #define ll long long usi…

页面事件的控制

1.设置默认焦点ASP.NET1.1中设置方法&#xff1a;<body onload"document.getElementById(TextBox1).focus();"><body onkeydown"document.all(TextBox1).focus();">ASP.NET2.0中设置方法&#xff1a;<form id"Form1"method"…

简而言之,JUnit:测试结构

尽管存在关于JUnit测试的书籍和文章&#xff0c;但我仍然经常遇到程序员&#xff0c;他们至多对这个工具及其正确用法都不甚了解。 因此&#xff0c;我想到了编写多部分教程的想法&#xff0c;从我的角度解释了要点。 也许在这个小型系列中采用的动手方法可能适合使一两个额外…

cf1207解题报告

cf1207解题报告 A 模拟 #include <bits/stdc.h> #define ll long long using namespace std; ll T,a,b,c,x,y; int main() {cin>>T;while(T --> 0) {cin>>a>>b>>c>>x>>y;ll ans0;if(x>y) {while(a>2&&b>1) ansx…

Oracle 用脚本安装第二个数据库

安装第二个数据库&#xff1a;登录oracle用户进入家目录&#xff0c;添加配置环境变量&#xff1a;vi .bash_profier ORACLE_SIDprod2临时环境变量&#xff1a;$export ORACLE_HOME/u01/app/oracle/product/11.2.0/db_1 $export ORACLE_SIDprod2创建第二个数据库文件目录&#…

深入学习jQuery鼠标事件

前面的话 鼠标事件是DOM事件中最常用的事件&#xff0c;jQuery对鼠标事件进行了封装和扩展。本文将详细介绍jQuery鼠标事件 类型 鼠标事件共10类&#xff0c;包括click、contextmenu、dblclick、mousedown、mouseup、mousemove、mouseover、mouseout、mouseenter和mouseleave c…

智能自动PPR更改事件策略

ADF开发人员普遍认为&#xff0c;将迭代器绑定更改事件策略设置为ppr在性能方面不是一件好事&#xff0c;因为此策略会强制框架刷新每个请求上绑定到此迭代器的所有属性绑定。 这不是真的&#xff01; 框架仅刷新在请求期间已更改的属性和依赖于已更改属性的属性。 让我们考虑…

[转]国际化: 理解Java平台上的Locale

From:http://jatula.javaeye.com/blog/183680 语言和地理环境对我们的文化产生重要影响.我们同他人之间的交流以及生活中的事件都发生在语言和地理环境所产生的一个系统里.由于语言和环境的不同,以至 需要我们来制定一个适合的方式来达到向他人表述我们自己或者我们的想法的目的…

深入学习jQuery描述文本内容的3个方法

前面的话 在javascript中&#xff0c;描述元素内容有5个属性&#xff0c;分别是innerHTML、outerHTML、innerText、outerText和textContent。这5个属性各自有各自的功能&#xff0c;且兼容性不同。jQuery针对这样的处理提供了3个便捷的方法&#xff0c;分别是&#xff1a;html(…

luoguP4551最长异或路径

P4551最长异或路径 链接 luogu 思路 从\(1\)开始\(dfs\)求出\(xor\)路径。然后根据性质\(x\)到\(y\)的\(xor\)路径就是\(xo[x]^xo[y]\) 代码 #include <bits/stdc.h> using namespace std; const int _1e57; int xo[_],w[_],ans-1,num0; struct node {int v,q,nxt; }e[_&…

谈一谈我的996 (随笔)

说一说996这个最近技术圈比较热门的话题。 什么是996&#xff0c;早九晚九一周上班6天。 看朋友圈&#xff0c;有个朋友说自己没有经历过什么是996&#xff0c;感觉自己是个假的程序员&#xff0c;是不是程序员就应该加班呢&#xff0c;是不是已经下意识&#xff0c;大众性的认…