概述

在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匿名函数和闭包相关推荐

  1. JavaScript 匿名函数与闭包

    匿名函数与闭包 匿名函数 闭包 概念 相关知识点 闭包中的this 循环函数中的匿名函数和闭包 循环函数中的匿名函数 循环函数中的闭包 模仿块级作用域 私有变量 静态私有变量 匿名函数 没有函数名的函 ...

  2. javascript匿名函数及闭包深入理解及应用

    1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式 第一种: ...

  3. javascript进阶课程--第三章--匿名函数和闭包

    javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...

  4. php的匿名函数和闭包函数

    php的匿名函数和闭包函数 tags: 匿名函数 闭包函数 php闭包函数 php匿名函数 function use 引言:匿名函数和闭包函数都不是特别高深的知识,但是很多刚入门的朋友却总是很困惑,因 ...

  5. 简单介绍Javascript匿名函数和面向对象编程

    忙里偷闲,简单介绍一下Javascript中匿名函数和闭包函数以及面向对象编程.首先简单介绍一下Javascript中的密名函数. 在Javascript中函数有以下3中定义方式: 1.最常用的定义方 ...

  6. js 匿名函数和闭包

    匿名函数和闭包 转https://www.cnblogs.com/xiaowie/p/10277483.html 填写了注释 匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数.声明: ...

  7. html 匿名函数调用,浅析Javascript匿名函数与自执行函数

    函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 函数的定义,大致可分为三种方式: 第一种:这也是最常规的一种 function doubl ...

  8. javascript匿名函数的理解

    复制粘贴 [color=red]点评:请记住,关键点是理解javascript的函数概念(参考w3cshool对函数的描述,搜索关键字:ECMAScript 函数).以及()的运算的理解. 比如:va ...

  9. 深入理解Java Lambda表达式,匿名函数,闭包

    前言 对于Lambda表达式一直是知其然不知其所以然,为了搞清楚什么是Lambda表达式,以及Lambda表达式的用法和作用,本文应运而生当做学习笔记分享出来,欢迎指正交流. 什么是Lambda 让我 ...

最新文章

  1. 第八章 软件项目质量计划
  2. rabbitmq 入门demo
  3. Facebook 被指收集用户数据:通过照片和文本
  4. Sybase插入数据库遭遇sybase Unexpected EOF encountered in BCP data-file.
  5. 67 cookie常用方法
  6. 冒泡排序法:一维数组 (最费内存资源的排序法)
  7. eclipse导入maven项目
  8. NUC1041 数字三角形【DP】
  9. TechNet Plus订阅版再度推出6折优惠
  10. 专家视点:杜绝木马的干扰-防范后门的技巧(转)
  11. 小米盒子 smb Android,客厅里的多媒体 小米盒子SMB本地连接
  12. gitlab 添加了 ssh keys, git clone git@xxx:xx.git 无法拉取的解决思路及办法
  13. 复制粘贴到word文档中的表格超出页面该怎么办
  14. 股票实时数据如何分析?
  15. led灯光衰怎么解决_解决LED灯具光衰办法大全
  16. body 没有被撑开_flex布局被子元素撑开如何保持内容不超出容器的方法
  17. 45. Django 2.1.7 项目技巧 - 创建apps应用目录归纳所有应用
  18. Cpolar实现虚拟机内网穿透,搭建私人云服务器
  19. MT4 CRM 系统开发(一)
  20. java中jar文件

热门文章

  1. Linux环境下安装Oracle 11g R2完整图文教程
  2. Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255]
  3. 99%的人都不懂中本聪、V神这么牛靠的是什么?一张图而已!
  4. 计算机多媒体对语文教学的提高,终于懂了语文教学如何利用多媒体
  5. (转)李开复的美东AI见闻
  6. 从 .NET 开发人员的角度理解 Excel 对象模型 (From MSDN)
  7. 【决策树算法】泰坦尼克号乘客生存预测
  8. JavaScript实现无缝轮播图效果
  9. 黄章出山的730天:牢牢掌控魅族,绝不放权!
  10. 【Git】git push -u origin master 的含义和 -u 的含义