JavaScript匿名函数和闭包
概述
在JavaScript前端开发中,函数与对其状态即词法环境(lexical environment)的引用共同构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript,函数在每次创建时生成闭包。匿名函数和闭包可以放在一起学习,可以加深理解。本文主要通过一些简单的小例子,简述匿名函数和闭包的常见用法,仅供学习分享使用,如有不足之处,还请指正。
普通函数
普通函数由fucntion关键字,函数名,() 和一对{} 组成,如下所示:
function box(){return 'Hex';
}
alert(box());
匿名函数
顾名思义,匿名函数就是没有实际名字的函数。单独的匿名函数无法运行,如下所示:
function (){return 'Hex';
}
//以上,会报错:缺少标识符
如何解决匿名函数不能执行的问题呢?有如下几种方法:
1. 把匿名函数赋值给变量,如下所示:
//把匿名函数赋值给变量
var box=function(){return 'Hex';
}
alert(box());
2. 通过自我执行来调用函数,格式如下:(匿名函数)()
(function(){alert('Hex');
})();
3. 把匿名函数自我执行的返回值赋值给变量,如下所示:
var box=(function(){return 'Hex';
})();
alert(box);//注意:此处不带括弧
4. 或者省去变量,如下所示:
alert((function() {return 'Hex';
})());
自我执行匿名函数如何传递参数呢?如下所示:
(function(age) {alert('Hex--' + age);
})(30);
闭包(closure)
闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。简单理解:函数里面套函数,子函数可以访问父函数的作用域里面的变量。
1. 函数里面放匿名函数,如下所示:
function box(){//闭包return function(){return 'Hex';}
}
alert(box()());
//或者
var b=box();
alert(b());
2. 通过闭包返回局部变量,使用闭包可以有一个优点,和是它的缺点,可以是局部变量驻留在内存中。
function box(){var age=100;//此变量为函数的局部变量,外部无法访问return function(){return age;}
}
alert(box()());
闭包和全局变量相比较
1. 使用全局变量累加,如下所示:
var age=100;
function box(){age++;
}
alert(age);
box();
alert(age);
box();
alert(age);
2. 使用局部变量累加,如下所示:
function box(){var age=100;age++;return age;
}
alert(box());//无法实现累加
alert(box());//无法实现累加
alert(box());//无法实现累加
3. 使用闭包实现累加,如下所示:
function box(){var age=100;return function(){age++;return age;}
}
var b=box();//将返回值赋值给b
alert(b());//实现累加
alert(b());//实现累加
alert(b());//实现累加
b=null;//使用闭包在调用结束时不会立即销毁内存,导致性能下降,所以需要解除占用
差异:使用全局变量,容易引起命名冲突,且系统性能下降。
循环匿名函数取值问题
1. 循环里的匿名函数取值问题,如下所示:没有实现arr[0]=0,arr[1]=1 ...arr[4]=4的效果
function box(){var arr=[];for (var i=0;i<5;i++) {arr[i]=function(){return i;}}//函数返回之前,循环已经结束,i=5return arr;
}
var b=box();
for (var i=0;i<5;i++) {alert(b[i]()); //此时返回的都是5,没有实现arr[0]=0,arr[1]=1 ...arr[4]=4的效果
}
以上问题如何优化呢?
方法1,直接赋值,不采用闭包,如下所示:
function box(){var arr=[];for (var i=0;i<5;i++) {arr[i]=i; //直接赋值}//函数返回之前,循环已经结束,i=5return arr;
}
var b=box();
for (var i=0;i<5;i++) {alert(b[i]);
}
方法2,通过匿名函数的自我执行,如下所示:
function box(){var arr=[];for (var i=0;i<5;i++) {arr[i]=(function(num){//此处可以有其他一些逻辑return num;})(i);}return arr;
}
var b=box();
for (var i=0;i<5;i++) {alert(b[i]);
}
方法3,将变量驻留在内存中,如下所示:
function box(){var arr=[];for (var i=0;i<5;i++) {arr[i]=(function(num){//此处可以有其他一些逻辑return function(){return num;};})(i);}return arr;
}
var b=box();
for (var i=0;i<5;i++) {alert(b[i]());
}
关于this的指向问题
对于对象内部,this指向对象本身,如下所示:
var box={getThis:function(){return this;}
};
alert(box.getThis());//输出[object Object] //此处this指box对象
var user='The window';
var box={user:'The box',getUser:function(){return this.user;}
}
alert(box.getUser());//输出:the box
this在闭包中,指示window对象,所以闭包在运行时指向window,如下所示:
var box1 ={getThis:function(){return function(){return this;}}
};
alert(box1.getThis()()); //输出[object Window]//此处this是window对象
var box1={user:'The box',getUser:function(){//此处的作用域是box1return function(){//此处的作用域是widowreturn this.user;};}
}
alert(box1.getUser()());//输出:the window ,表示闭包在运行时模拟this指向window
如何让闭包的this指向box呢?可以有如下两种方法,如下所示:
alert(box1.getUser().call(box1));//对象冒充
//可以将box的作用域对象传递给闭包
var box1={user:'The box',getUser:function(){var that=this;return function(){return that.user;};}
}
alert(box1.getUser()());
缺点:闭包无法释放对象,容易导致内存泄漏,如下所示:
function box(){var a1=document.getElementById('A01');var txt=a1.innerHTML;a1.onclick=function(){//如果a1为null,则会报错//alert(a1.innerHTML);//点击事件获取内容,alert(txt);}//如无下面一句,则会导致内存无法释放对象a1a1=null;//此处需要手动将a1释放,等待回收
}
box();
块级作用域
模仿块级作用域,面向对象的思想,封装变量。普通函数没有块级作用域的概念,如下所示:
function box(){for (var i=0;i<5;i++) {}alert(i);//输出:5,表示出了for语句块,i依然可以访问
}
box();
如何让i私有化,出了作用域,不可以访问呢?可以采用匿名函数的自我执行,则出了作用域就会访问不到,如下所示:
function box(){(function(){for (var i=0;i<5;i++) {}})();//alert(i);//报错:提示“i”未定义
}
box();
全局变量的私有作用域,减少变量的命名冲突,如下所示:
(function(){//此处就是全局作用域里面的私有作用域var age=100;alert(age);
})();
//alert(age);报错:提示“age”未定义
普通函数和构造函数的区别:首字母大写。如下所示:对象的属性和函数都是public类型的
function Box(){this.age=100; //此处是公有属性,无法私有化//函数也是公有函数this.run=function(){return 'running....';}
}
var box=new Box();
alert(box.age); //通过对象可以访问
alert(box.run());//通过对象可以访问
如何将公有属性,私有化呢? 如下所示:
function Box(){var age=100;//私有变量,外部访问不到function run(){//私有函数,外部访问不到return 'running....';}//对外公布的访问接口,可以访问私有内容this.go=function(){return age+' '+run();}
}
var box=new Box();
alert(box.go());
通过构造函数传递参数,如下所示:
function Box(v){var user=v;this.getUser=function(){return user;};this.setUser=function(v){user=v;}
}
var box=new Box('Hex');
alert(box.getUser());
//对象方法可以在创建的时候,创建多次
注意:通过构造函数创建对象,在每次创建的时候,都会分配不同的地址。
静态私有变量
采用静态私有变量,可以实现数据的共享,如下所示:
(function(){var user=''; //私有变量Box=function(value){//必须全局构造函数,将匿名函数赋值给Box,否则外部无法访问user=value;}Box.prototype.getUser=function(){return user;};Box.prototype.setUser=function(value){user=value;};
})();
var box=new Box('AAAA'); //第一次实例化
alert(box.getUser());//输出AAAA
var box2=new Box('BBBB');//第二次实例化
alert(box.getUser());//输出BBBB
单例对象
单例即只有一个实例化的对象,可以有两种实现方式。
1. 通过字面量的方式实现,如下所示:
var box={user:'hex',go:function(){return user+' is running....';}
};
alert(box.go());
2. 通过匿名函数的自我执行返回对象的方式实现,如下所示:
var box=function(){var user='Hex'; //私有变量function run(){ //私有函数return ' is running....';}//返回一个对象var obj= {//公共特权方法going:function(){return user+run();}}return obj;
}();
alert(box.going());
备注
望岳
作者:杜甫 (唐)
岱宗夫如何?齐鲁青未了。
造化钟神秀,阴阳割昏晓。
荡胸生曾云,决眦入归鸟。
会当凌绝顶,一览众山小。
JavaScript匿名函数和闭包相关推荐
- JavaScript 匿名函数与闭包
匿名函数与闭包 匿名函数 闭包 概念 相关知识点 闭包中的this 循环函数中的匿名函数和闭包 循环函数中的匿名函数 循环函数中的闭包 模仿块级作用域 私有变量 静态私有变量 匿名函数 没有函数名的函 ...
- javascript匿名函数及闭包深入理解及应用
1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式 第一种: ...
- javascript进阶课程--第三章--匿名函数和闭包
javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...
- php的匿名函数和闭包函数
php的匿名函数和闭包函数 tags: 匿名函数 闭包函数 php闭包函数 php匿名函数 function use 引言:匿名函数和闭包函数都不是特别高深的知识,但是很多刚入门的朋友却总是很困惑,因 ...
- 简单介绍Javascript匿名函数和面向对象编程
忙里偷闲,简单介绍一下Javascript中匿名函数和闭包函数以及面向对象编程.首先简单介绍一下Javascript中的密名函数. 在Javascript中函数有以下3中定义方式: 1.最常用的定义方 ...
- js 匿名函数和闭包
匿名函数和闭包 转https://www.cnblogs.com/xiaowie/p/10277483.html 填写了注释 匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数.声明: ...
- html 匿名函数调用,浅析Javascript匿名函数与自执行函数
函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 函数的定义,大致可分为三种方式: 第一种:这也是最常规的一种 function doubl ...
- javascript匿名函数的理解
复制粘贴 [color=red]点评:请记住,关键点是理解javascript的函数概念(参考w3cshool对函数的描述,搜索关键字:ECMAScript 函数).以及()的运算的理解. 比如:va ...
- 深入理解Java Lambda表达式,匿名函数,闭包
前言 对于Lambda表达式一直是知其然不知其所以然,为了搞清楚什么是Lambda表达式,以及Lambda表达式的用法和作用,本文应运而生当做学习笔记分享出来,欢迎指正交流. 什么是Lambda 让我 ...
最新文章
- 第八章 软件项目质量计划
- rabbitmq 入门demo
- Facebook 被指收集用户数据:通过照片和文本
- Sybase插入数据库遭遇sybase Unexpected EOF encountered in BCP data-file.
- 67 cookie常用方法
- 冒泡排序法:一维数组 (最费内存资源的排序法)
- eclipse导入maven项目
- NUC1041 数字三角形【DP】
- TechNet Plus订阅版再度推出6折优惠
- 专家视点:杜绝木马的干扰-防范后门的技巧(转)
- 小米盒子 smb Android,客厅里的多媒体 小米盒子SMB本地连接
- gitlab 添加了 ssh keys, git clone git@xxx:xx.git 无法拉取的解决思路及办法
- 复制粘贴到word文档中的表格超出页面该怎么办
- 股票实时数据如何分析?
- led灯光衰怎么解决_解决LED灯具光衰办法大全
- body 没有被撑开_flex布局被子元素撑开如何保持内容不超出容器的方法
- 45. Django 2.1.7 项目技巧 - 创建apps应用目录归纳所有应用
- Cpolar实现虚拟机内网穿透,搭建私人云服务器
- MT4 CRM 系统开发(一)
- java中jar文件
热门文章
- Linux环境下安装Oracle 11g R2完整图文教程
- Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255]
- 99%的人都不懂中本聪、V神这么牛靠的是什么?一张图而已!
- 计算机多媒体对语文教学的提高,终于懂了语文教学如何利用多媒体
- (转)李开复的美东AI见闻
- 从 .NET 开发人员的角度理解 Excel 对象模型 (From MSDN)
- 【决策树算法】泰坦尼克号乘客生存预测
- JavaScript实现无缝轮播图效果
- 黄章出山的730天:牢牢掌控魅族,绝不放权!
- 【Git】git push -u origin master 的含义和 -u 的含义