JavaScript 闭包系列二(匿名函数及函数的闭包)
一. 匿名函数
1. 函数的定义,可分为三种
1) 函数声明方式
function double(x) {
return 2*x;
}
2)Function构造函数,把参数列表和函数体都作为字符串,不方便,不建议使用
var double = new Function('x', 'return 2*x;');
3)函数表达式方式
var double = function(x) {
return 2*x;
}
该形式中,等号右边是一个匿名函数,创建函数完毕后,将该函数赋给了变量double。
2. 匿名函数
1)第一种方式
var double= function(x) {
return 2*x;
}
等号右边是一个匿名函数。注意匿名函数不能直接独立的房子代码中,如下代码
functino(x) {
return 2*x;
} //SyntaxError: Unexpected token (
2)第二种方式
(function(x,y) {
console.log(x+y);
})(2,3);
创建一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数并传入参数。
二. 闭包(Closure)
闭包的含义:外层函数包含内层函数,内层函数可以访问外层函数的所有变量,即使外层函数执行完毕。(JavaScript作用域链)
题外话:上述对于闭包的解释与《JavaScript 闭包系列一》中不完全吻合。 上述解释,闭包成立只需满足:函数inner嵌套在函数outer内部。另一些文章对于闭包的解释,闭包成立需要两个条件:1)函数inner嵌套在函数outer内部;2)函数outer返回函数inner。对此,我已经凌乱了,各路大侠谁能够给个定论?
Example 1:
函数outer是瞬间执行的(约0.00001毫秒),在函数outer体内创建了一个变量str,在outer执行完毕后,str变量未被释放,这是由于setTimeout内的匿名函数存在对变量str的引用。等到2秒后,匿名函数执行完毕,str才被释放。
function outer() {
var str = "closure";
setTimeout(function() {
console.log(str);
}, 2000);
}
outer(); //closure
Example 2:此例是否为闭包呢?
function outer() {
var i = 22;
(function inner() {
console.log(i);
})();
}
outer(); //
Example 3:简化代码
function forTimeout(x, y) {
console.log(x + y);
}
function delay(x, y, time) {
setTimeout('forTimeout(' + x + ',' + y + ')', time);
}
//简化后
function delay(x, y, time) {
setTimeout(
function() {
forTimeout(x,y);
}
,time);
}
delay(3, 4, 2000); //
三. 匿名函数与闭包
匿名函数的最大用途是创建闭包,它也可用来构建命名空间,减少全局变量的使用。
Example1:
匿名函数中的addEvent和removeEvent为局部变量,但是可以通过全局变量oEvent使用它,大大减少了全局变量的使用,增强了网页的安全性。
var oEvent = {};
(function() {
var addEvent = function() {};
function removeEvent(){}
oEvent.addEvent = addEvent;
oEvent.removeEvent = removeEvent;
})();
Example2:
创建一个变量sun_mile_rain,并通过直接调用匿名函数初始化为5,这种小技巧有时十分有用。
var sun_mile_rain = (function(x , y){
return x + y;
})(2 , 3);
console.log(sun_mile_rain); //
//也可使用如下的方式,第一个括号只是帮助我们阅读,但是不推荐下面这种书写格式
var sun_mile_rain = function(x , y){
return x + y;
}(2 , 3);
Example3:
代码中,变量one定义在函数内部,是一个局部变量,因此外部是不可以访问的。但inner函数可以访问变量one,又将全局变量outer引用了inner,因此执行outer()能访问到one的值。
var outer = null;
(function() {
var one = 1;
function inner() {
one += 1;
console.log(one);
}
outer = inner;
})();
outer(); //
outer(); //
outer(); //
换一种形式:函数fn执行,返回inner,将fn的执行结果赋给全局变量outer。执行outer也能访问到one的值。因此可得知闭包的形式可以有多种。
function fn() {
var one = 1;
function inner() {
one += 1;
console.log(one);
}
return inner;
}
var outer = fn();
outer(); //
outer(); //
outer(); //
四. 闭包与变量
闭包允许内层函数引用父函数中的变量,但该变量是最终值。
鼠标移过每一个li元素时,控制台输出的值都是3,而不是我们期望的元素下标。当mouseover事件调用监听函数时,首先在匿名函数内部查找i是否定义,结果没找到,因此向上查找,在全局环境中找到i,并且i的值是3(循环后的值)。因此每次输出的都是3。
/*
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
*/
var lists = document.getElementsByTagName("li");
for(var i=0; i<lists.length; i++) {
lists[i].onmouseover = function() {
console.log(i);
}
}
注意:此处的闭包,并不是函数嵌套函数的形式,而是匿名函数包含在全局环境中的形式。
针对上述代码,有三种方法改进,使得鼠标移动到li元素上时,控制台输出对应的下标值。
1)立即执行的匿名函数
var lists = document.getElementsByTagName("li");
for (var i = 0; i < lists.length; i++) {
(function(index) {
lists[i].onmouseover = function() {
console.log(index);
};
})(i);
}
2)在DOM元素上绑定$$index属性记录下标
var lists = document.getElementsByTagName("li");
for (var i = 0; i < lists.length; i++) {
lists[i].$$index = i;
lists[i].onmouseover = function() {
console.log(this.$$index);
};
}
3)
var lists = document.getElementsByTagName("li");
for (var i = 0; i < lists.length; i++) {
eventListener(lists[i],i);
}
function eventListener(list,index) {
list.onmouseover = function() {
console.log(index);
}
}
时间:2014-10-23
地点:合肥
引用:http://www.cnblogs.com/rainman/archive/2009/05/04/1448899.html
JavaScript 闭包系列二(匿名函数及函数的闭包)的更多相关文章
- Javascript数组系列二之迭代方法1
我们在<Javascript数组系列一之栈与队列 >中介绍了一些数组的用法.比如:数组如何表现的和「栈」一样,用什么方法表现的和「队列」一样等等一些方法,因为 Javascript 中的数 ...
- Javascript基础系列之(七)函数(定义和调运函数)
函数是一个可以随时运行的语句,简单说,函数是完成某个功能的一组语句,它接受0或者多个参数. 函数的基本语法如下 function functionName([arg0,arg1,......argN] ...
- Javascript基础系列之(七)函数(argument访问函数参数)
argument是javascript中函数的一个特殊参数,例如下文,利用argument访问函数参数,判断函数是否执行 <script type="text/javascript&q ...
- Javascript基础系列之(七)函数(对象和属性)
包含在对象里的数据可以通过两种方式来访问 既属性的对象(property)和方法(method) 属性是隶属于某个特定对象的变量,方法则是某个特定对象才能调运的函数. 对象是由一些彼此相关的属性和方法 ...
- Javascript设计模式系列二
创建对象的基本模式,一.门户大开型,二.采用下划线来表示属性和方法的私用性,三.使用闭包来创建私用的成员. 一.门户大开型.只能提供公用成员.所有属性和方法都公开的.可访问的.这些共用属性都要使用th ...
- javascript设计模式系列二-封装
JavaScript封装: var Book = function (id, name, price) { this.id = id, this.name = name, this.price = p ...
- js匿名自执行函数中闭包的高级使用(---------------------------******-----------------------------)
先看看最常见的一个问题: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- Javascript数组系列三之迭代方法2
今天我们来继续 Javascript 数组系列的文章,上文 <Javascript数组系列二之迭代方法1> 我们说到一些数组的迭代方法,我们在开发项目实战的过程中熟练的使用可以大大提高我们 ...
- Javascript数组系列五之增删改和强大的 splice()
今天是我们介绍数组系列文章的第五篇,也是我们数组系列的最后一篇文章,只是数据系列的结束,所以大家不用担心,我们会持续的更新干货文章. 生命不息,更新不止! 今天我们就不那么多废话了,直接干货开始. 我 ...
随机推荐
- Java生成随机验证码
package com.tg.snail.core.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphic ...
- jdbc.properties各种数据库连接配置
# HSQLDB #jdbc.driverClassName=org.hsqldb.jdbcDriver #jdbc.url=jdbc:hsqldb:hsql://localhost:9001/bo ...
- angularjs指令系统系列课程(3):替换replace,内容保留transclude,作用方式restrict
这一节我们主要看一下replace,transclude,restrict这三个参数 1.replace 可取值:bool 默认为:true 对于replace属性,设置为false表示原有指令标识不 ...
- road习题(一)
答案:[D] 答案:[C] 分析需要靠人 答案:[B] 答案:[B] c语言本身支持自定义函数 答案:[B] Virtual User Generator:是一个脚本开发组件 说白了就是虚拟机用户发生 ...
- SublimeText2 快捷键一览表
SublimeText2 快捷键一览表 Sublime Text比起Notepad++,UltraEdit之类Code编辑器来说,其功能有过之而无不及,配合着各种插件使用,Sublime Text在实 ...
- Strus2第一次课:dom4j解析xml文档
xml文本标记语言: 常用于交换数据:独立于操作系统.编程语言数据存储:xml数据配置:灵活性强,可读性高可以使用css样式改变xml样式 xml解析技术:dom解析xml技术: sax解析xml技术 ...
- 流媒体测试笔记记录之————阿里云监控、OBS、FFmpeg拉流和推流变化比较记录
OBS设置视频(512kbps)和音频(128kbps)比特率 阿里云监控结果: 使用FFmpeg拉流到Nginx 服务器测试比特率 第二次测试,修改视频和音频比特率 OBS设置 阿里云监控 Ngin ...
- 【转】Python3.x和Python2.x的区别
这个星期开始学习Python了,因为看的书都是基于Python2.x,而且我安装的是Python3.1,所以书上写的地方好多都不适用于Python3.1,特意在Google上search了一下3.x和 ...
- maven工程使用spring-boot-devtools进行热部署,更改代码避免重启web容器
spring-boot-devtools 是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去.相关Blog: 点击打开链接 原理是在发现代码有更改之后,重新启动应用 ...
- 准循环LDPC码用于公钥密码时的奇偶校验矩阵
设H为奇偶校验矩阵,其行权重为d.Q为转置矩阵,其行权重为m.对于LDPC码,有d/n<< 1, m/n< 1. H´=H·QT是用于公钥密码的奇偶校验矩阵.它不是老密码G的奇偶校验 ...