当前位置:文档之家› 详谈JavaScript 匿名函数及闭包

详谈JavaScript 匿名函数及闭包

详谈JavaScript 匿名函数及闭包
详谈JavaScript 匿名函数及闭包

详谈JavaScript 匿名函数及闭包

1、匿名函数

函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途。匿名函数:就是没有函数名的函数。

1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式

第一种:这也是最常规的一种

代码如下:

function double(x){

return 2 * x;

}

第二种:这种方法使用了Function构造函数,把参数列表和函数体都作为字符串,很不方便,不建议使用。

代码如下:

var double = new Function('x', 'return 2 * x;');

第三种:

var double = function(x) { return 2* x; }

注意“=”右边的函数就是一个匿名函数,创造完毕函数后,又将该函数赋给了变量square。

1.2 匿名函数的创建

第一种方式:就是上面所讲的定义square函数,这也是最常用的方式之一。

第二种方式:

代码如下:

(function(x, y){

alert(x + y);

})(2, 3);

这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。

2、闭包

闭包的英文单词是closure,这是JavaScript中非常重要的一部分知识,因为使用闭包可以大大减少我们的代码量,使我们的代码看上去更加清晰等等,总之功能十分强大。

闭包的含义:闭包说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕(这点涉及JavaScript作用域链)。

示例一

代码如下:

function checkClosure(){

var str = 'rain-man';

setTimeout(

function(){ alert(str); } //这是一个匿名函数

, 2000);

}

checkClosure();

这个例子看上去十分的简单,仔细分析下它的执行过程还是有许多知识点的:checkClosure 函数的执行是瞬间的(也许用时只是0.00001毫秒),在checkClosure的函数体内创建了一个变量str,在checkClosure执行完毕之后str并没有被释放,这是因为setTimeout内的匿名函数存在这对str的引用。待到2秒后函数体内的匿名函数被执行完毕,str才被释放。

示例二,优化代码

代码如下:

function forTimeout(x, y){

alert(x + y);

}

function delay(x , y , time){

setTimeout('forTimeout(' + x + ',' + y + ')' , time);

}

/**

* 上面的delay函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰

* function delay(x , y , time){

* setTimeout(

* function(){

* forTimeout(x , y)

* }

* , time);

* }

3、举例

匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

示例三:

代码如下:

var oEvent = {};

(function(){

var addEvent = function(){ /*代码的实现省略了*/ };

function removeEvent(){}

oEvent.addEvent = addEvent;

oEvent.removeEvent = removeEvent;

})();

在这段代码中函数addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent 使用它,这就大大减少了全局变量的使用,增强了网页的安全性。我们要想使用此段代码:oEvent.addEvent(document.getElementById('box') , 'click' , function(){});

示例四:

代码如下:

var rainman = (function(x , y){

return x + y;

})(2 , 3);

/**

* 也可以写成下面的形式,因为第一个括号只是帮助我们阅读,但是不推荐使用下面这种书写格式。

* var rainman = function(x , y){

* return x + y;

* }(2 , 3);

*/

在这里我们创建了一个变量rainman,并通过直接调用匿名函数初始化为5,这种小技巧有时十分实用。

示例五:

代码如下:

var outer = null;

(function(){

var one = 1;

function inner (){

one += 1;

alert(one);

}

outer = inner;

})();

outer(); //2

outer(); //3

outer(); //4

这段代码中的变量one是一个局部变量(因为它被定义在一个函数之内),因此外部是不可以访问的。但是这里我们创建了inner函数,inner函数是可以访问变量one的;又将全局变量outer引用了inner,所以三次调用outer会弹出递增的结果。

4、注意

4.1 闭包允许内层函数引用父函数中的变量,但是该变量是最终值

示例六:

代码如下:

/**

*

*

*/

var lists = document.getElementsByTagName('li');

for(var i = 0 , len = lists.length ; i < len ; i++){

lists[ i ].onmouseover = function(){

alert(i);

};

}

你会发现当鼠标移过每一个

解决方法一:

代码如下:

var lists = document.getElementsByTagName('li');

for(var i = 0 , len = lists.length ; i < len ; i++){

(function(index){

lists[ index ].onmouseover = function(){

alert(index);

};

})(i);

}

解决方法二:

代码如下:

var lists = document.getElementsByTagName('li');

for(var i = 0, len = lists.length; i < len; i++){

lists[ i ].$$index = i; //通过在Dom元素上绑定$$index属性记录下标

lists[ i ].onmouseover = function(){

alert(this.$$index);

};

}

解决方法三:

代码如下:

function eventListener(list, index){

list.onmouseover = function(){

alert(index);

};

}

var lists = document.getElementsByTagName('li');

for(var i = 0 , len = lists.length ; i < len ; i++){

eventListener(lists[ i ] , i);

}

4.2 内存泄露

使用闭包十分容易造成浏览器的内存泄露,严重情况下会是浏览器挂死。可以参考下面内容预防:

JavaScript垃圾回收机制

JavaScript不需要手动地释放内存,它使用一种自动垃圾回收机制(garbage collection)。当一个对象无用的时候,即程序中无变量引用这个对象时,就会从内存中释放掉这个变量。复制代码代码如下:

var s = [ 1, 2 ,3];

var s = null;

//这样原始的数组[1 ,2 ,3]就会被释放掉了。

3、循环引用

三个对象A 、B 、C

AàBàC :A的某一属性引用着B,同样C也被B的属性引用着。如果将A清除,那么B、C也被释放。

AàBàCàB :这里增加了C的某一属性引用B对象,如果这是清除A,那么B、C不会被释放,因为B和C之间产生了循环引用。

复制代码代码如下:

var a = {};

a.pro = { a:100 };

a.pro.pro = { b:100 };

a = null ;

//这种情况下,{a:100}和{b:100}就同时也被释放了。

var obj = {};

obj.pro = { a : 100 };

obj.pro.pro = { b : 200 };

var two = obj.pro.pro;

obj = null;

//这种情况下{b:200}不会被释放掉,而{a:100}被释放了。

4、循环引用和闭包

复制代码代码如下:

function outer(){

var obj = {};

function inner(){

//这里引用了obj对象

}

obj.inner = inner;

}

这是一种及其隐蔽的循环引用,。当调用一次outer时,就会在其内部创建obj和inner两个对象,obj的inner属性引用了inner;同样inner也引用了obj,这是因为obj仍然在inn erFun的封闭环境中,准确的讲这是由于JavaScript特有的“作用域链”。

因此,闭包非常容易创建循环引用,幸运的是JavaScript能够很好的处理这种循环引用。

5、IE中的内存泄漏

IE中的内存泄漏有好几种,这里有详细的解释(https://www.doczj.com/doc/1d10513451.html,/en-us/libra ry/bb250448.aspx)。

这里只讨论其中一种,即循环引用所造成的内存泄漏,因为,这是一种最普遍的情况。

当在DOM元素或一个ActiveX对象与普通JavaScript对象之间存在循环引用时,IE在释放这类变量时存在特殊的困难,最好手动切断循环引用,这个bug在IE 7中已经被修复了(https://www.doczj.com/doc/1d10513451.html,/blog/archives/2006/04/ie_7_and_javasc.html)。

“IE 6 suffered from memory leaks when a circular reference between several objec ts, among which at least one DOM node, was created. This problem has been solved in IE 7. ”

如果上面的例子(第4点)中obj引用的不是一个JavaScript Function对象(inner),而是一个ActiveX对象或Dom元素,这样在IE中所形成的循环引用无法得到释放。

复制代码代码如下:

function init(){

var elem = document.getElementByid( 'id' );

elem.onclick = function(){

alert('rain-man');

//这里引用了elem元素

};

}

Elem引用了它的click事件的监听函数,同样该函数通过其作用域链也引用回了elem元素。这样在IE中即使离开当前页面也不会释放这些循环引用。

6、解决方法

基本的方法就是手动清除这种循环引用,下面一个十分简单的例子,实际应用时可以自己构建一个addEvent()函数,并且在window的unload事件上对所有事件绑定进行清除。复制代码代码如下:

function outer(){

var one = document.getElementById( 'one' );

one.onclick = function(){};

}

window.onunload = function(){

var one = document.getElementById( 'one' );

one.onclick = null;

};

其它方法(by:Douglas Crockford)

复制代码代码如下:

/**

* 遍历某一元素节点及其所有后代元素

*

* @param Elem node 所要清除的元素节点

* @param function func 进行处理的函数

*

*/

function walkTheDOM(node, func) {

func(node);

node = node.firstChild;

while (node) {

walkTheDOM(node, func);

node = node.nextSibling;

}

}

/**

* 清除dom节点的所有引用,防止内存泄露

*

* @param Elem node 所要清除的元素节点

*

*/

function purgeEventHandlers(node) {

walkTheDOM(node, function (e) {

for (var n in e) {

if (typeof e[n] ===

'function') {

e[n] = null;

}

}

});

以上就是JavaScript内存泄漏的相关内容以及解决方案了,有需要的小伙伴可以参考下

JS数学函数的调用

1 SQRT1_ 2 属性返回 2 的平方根的倒数。这个值近似为 0.7071067811865476。语法 Math.SQRT1_2 实例 返回 1/2 的平方根: 输出: SQRT1_2: 0.7071067811865476 2 SQRT2 属性返回 2 的平方根。这个值近似为 1.4142135623730951。 语法 Math.SQRT2 实例 返回 2 的平方根: 输出: SQRT2: 1.4142135623730951

3 strike() 方法用于显示加删除线的字符串。 语法 stringObject.strike() 实例 在本例中,"Hello world!" 将被加上一条删除线: 4 String() 函数把对象的值转换为字符串。 语法 String(object) 参数描述 object 必需。JavaScript 对象。 实例 在本例中,我们将尝试把不同的对象转换为字符串: 对于 javascript 的从业者可以试着运行下。看看你的答案和实际输出一致吗?别小看这样两 行脚本,这样的题目被当作 JavaScript 的笔试或者面试题目是常有的事情。 实际输出结果为:“undefined”, 这种现象被称成“预解析”:JavaScript 脚本引擎优先解析 var 变量和 function 定义。在预解析 完成后,才会执行代码。 由于变量 i 是被 var 声明的,而被优先解析。所以可以理解为在 alert(i) 执行时候,程序前 面已经有 var i; 所以上面代码等效解释为: 注意:预解析不会报错,因为他只解析正确的声明。 (2). 解释(主要指词法分析,生成语法树的过程) 请注意,这里‘解释’的定义是笔者自己方便理解自己定义的,而这个‘解释’并不在预解 析之后。 我们知道 JavaScript 是脚本语言,脚本语言是相对于高级编译型语言而言他是解释性的。解 释性语言没有编译成二进制代码,但是要进入到运行阶段,都应该是会经过词法分析、语法 分析生成语法树、语义检查过程,笔者把这个环节叫做“解释”,如果读者有更科学的名字记 得告诉我。 解释性语言在生成语法树后,就可以执行了。(这个跟脚本引擎编译器有关)

Javascript自执行匿名函数(function { }) 的原理浅析

Javascript自执行匿名函数(function { }) 的原理浅析 匿名函数就是没有函数名的函数。这篇文章主要介绍了Javascript自执行匿名函数(function { }) 的原理浅析的相关资料,需要的朋友可以参考下 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途。匿名函数指没有指定函数名或指针的函数,自执行匿名函数只是其中一种,下文中称这种函数为:自执行函数 下面是一个最常见的自执行函数: // 传统匿名函数 (function { alert('hello'); }) ; 这段代码的执行效果就是在页面再载入时弹出:"hello" 是什么促使它自动执行的?,来看下面的代码 // 在传统写法上去掉小括号,并在前面加上运算符~,!,+,- ~function { alert('hello'); } ;

!function { alert('hello'); } ; +function { alert('hello'); } ; -function { alert('hello'); } ; 这些写法与上文所说的传统方式执行起来并无区别, 我发现,这些写法的共同点是运算符,其实传统方式的小括号也属于运算的一种,出现在:a=b*(c+d),运算符 + 传递给自生的参数 = 函数自动执行?但有些符号也不支持,比如“=,*,/”号,它自执行的原因还是很神秘,网上也找不到像样的答案 然后我发现了一个神奇的现象,这些运算符可以无限叠加。。。。。。 // function前面是特定符号可以无限叠加... ~!+-~!+-+-!~!+-~!+-+-!~!+-~!+-+-!~!+-~!+-+-!~!+-~!+ -+-!~!+-~!+-+-!~!+-~!+-+-!~!+-~!+-+-!~!+-~!+-+-!~!+ -~!+-+-!~!+-~!+-+-!~!+-~!+-+-!~!+-~!+-+-!~!+-~!+-+-

JS系统函数

2008-01-29 js函数集 ·字符串(String) 1.声明 var myString = new String("Every good boy does fine."); var myString = "Every good boy does fine."; 2.字符串连接 var myString = "Every " + "good boy " + "does fine."; var myString = "Every "; myString += "good boy does fine."; 3.截取字符串 //截取第6 位开始的字符 var myString = "Every good boy does fine."; var section = myString.substring(6); //结果: "good boy does fine." //截取第0 位开始至第10 位为止的字符 var myString = "Every good boy does fine."; var section = myString.substring(0,10); //结果: "Every good" //截取从第11 位到倒数第6 位为止的字符 var myString = "Every good boy does fine."; var section = myString.slice(11,-6); //结果: "boy does" //从第6 位开始截取长度为4 的字符 var myString = "Every good boy does fine."; var section = myString.substr(6,4); //结果: "good" 4.转换大小写 var myString = "Hello"; var lcString = myString.toLowerCase(); //结果: "hello" var ucString = myString.toUpperCase(); //结果: "HELLO" 5.字符串比较 var aString = "Hello!"; var bString = new String("Hello!"); if( aString == "Hello!" ){ } //结果: true if( aString == bString ){ } //结果: true if( aString === bString ){ } //结果: false (两个对象不同,尽管它们的值相同) 6.检索字符串 var myString = "hello everybody."; // 如果检索不到会返回-1,检索到的话返回在该串中的起始位置 if( myString.indexOf("every") > -1 ){ } //结果: true 7.查找替换字符串 var myString = "I is your father."; var result = myString.replace("is","am"); //结果: "I am your father."

Javascript Closures

ECMAScript recognises two categories of object, "Native Object" and "Host Object" with a sub-category of native objects called "Built-in Object" (ECMA 262 3rd Ed Section 4.3). Native objects belong to the language and host objects are provided by the environment, and may be, for example, document objects, DOM nodes and the like. Native objects are loose and dynamic bags of named properties (some implementations are not that dynamic when it comes to the built in object sub-category, though usually that doesn't matter). The defined named properties of an object will hold a value, which may be a reference to another Object (functions are also Objects in this sense) or a primitive value: String, Number, Boolean, Null or Undefined. The Undefined primitive type is a bit odd in that it is possible to assign a value of Undefined to a property of an object but doing so does not remove that property from the object; it remains a defined named property, it just holds the value undefined. The following is a simplified description of how property values are read and set on objects with the internal details brushed over to the greatest extent possible. Assignment of Values Named properties of objects can be created, or values set on existing named properties, by assigning a value to that named property. So given:- var objectRef = new Object(); //create a generic javascript object. A property with the name "testNumber" can be created as:- objectRef.testNumber = 5; /* - or:- */ objectRef["testNumber"] = 5; The object had no "testNumber" property prior to the assignment but one is created when the assignment is made. Any subsequent assignment does not need to create the property, it just re-sets its value:- objectRef.testNumber = 8; /* - or:- */ objectRef["testNumber"] = 8; Javascript objects have prototypes that can themselves be objects, as will be described shortly, and that prototype may have named properties. But this has no role in assignment. If a value is assigned and the actual object does not have a property with the corresponding name a property of that name is created and the value is assigned to it. If it has the property then its value is re-set. Reading of Values It is in reading values from object properties that prototypes come into play. If an object has a property with the property name used in the property accessor then the value of that property is returned:- /* Assign a value to a named property. If the object does not have a property with the corresponding name prior to the assignment it will have one after it:- */ objectRef.testNumber = 8; /* Read the value back from the property:- */ var val = objectRef.testNumber; /* and - val - now holds the value 8 that was just assigned to the named property of the object. */

js时间函数(收藏)

js时间函数 * 博客分类:IT Flash 1.取得当前时间: var date=new Date(); 2.已知年、月、日转换成日期型的数据: var applyDate = document.domainExceptionForm.applyDate.value; applyDate = applyDate.split("T")[0]; var applyYear = applyDate.split("-")[0]; var applyMonth = applyDate.split("-")[1]-1; var applyDay = applyDate.split("-")[2]; var applyDate1 = new Date(applyYear,applyMonth,applyDay ); 3.比较两日期相差的天数是否大于5: parseInt((date-applyDate1) / (1000 * 60 * 60 * 24)) >= 5 4.比较两个时间: if(date.valueOf()>applyDate1.valueOf()) { alert("输入日期不得小于当前日期!"); } else { alert("OK!"); } 5.取得当前时间的时分秒 var tody=new Date(); var nian=tody.getFullYear(); var youe=tody.getMonth()+1; var day=tody.getDate(); var hour=tody.getHours(); var min=tody.getMinutes(); var miao=tody.getSeconds(); 6.时间相加:取得固定时间(2006年8月12日)35天之后的时间var d =new Date("2006,7,12"); d.setDate(d.getDate()+35); 7.Date对象的方法

作用域与闭包,js插件内部传递function()内部值

《作用域与闭包:this,var,(function () {})》目标 无具体目标 知识点 1.理解js 中var 的作用域 2.了解闭包的概念 3.理解this 的指向 课程内容 *es6中新增了let 关键词,与块级作用域,相关知识参 考:https://www.doczj.com/doc/1d10513451.html,/#docs/let * var 作用域 先来看个简单的例子: var parent=function () { var name ="parent_name"; var age =13; var child=function () { var name ="child_name"; var childAge =0.3;

// => child_name 13 0.3 console.log(name, age, childAge); }; child(); // will throw Error // ReferenceError: childAge is not defined console.log(name, age, childAge); }; parent(); 直觉地,内部函数可以访问外部函数的变量,外部不能访问内部函数的变量。上面的例子中内部函数child 可以访问变量age,而外部函数parent 不可以访问child 中的变量childAge,因此会抛出没有定义变量的异常。 有个重要的事,如果忘记var,那么变量就被声明为全局变量了。 function foo() { value ="hello"; }foo();console.log(value); // 输出hello console.log(global.value) // 输出hello 这个例子可以很正常的输出hello,是因为value变量在定义时,没有使 用var关键词,所以被定义成了全局变量。在Node 中,全局变量会被定义在global对象下;在浏览器中,全局变量会被定义在window对象下。

浅析MATLAB中的内联函数

浅析MATLAB中的内联函数、匿名函数和函数函数 原创,转载请注明出处……(不注明也拿你没办法) 内联函数 内联(inline)函数是MATLAB 7以前经常使用的一种构造函数对象的方法。在命令窗口、程序或函数中创建局部函数时,通过使用inline构造函数,而不用将其储存为一个M 文件,同时又可以像使用一般函数那样调用它。 MATLAB中的内联函数借鉴了C语言中的内联函数,在C语言中,内联函数是通过编译器控制来实现的,它只在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的时间和空间开销。在MATLAB中也有类似的性质。由于内联函数是储存于内存中而不是在M文件中,省去了文件访问的时间,加快了程序的运行效率。 虽然内联函数有M文件不具备的一些优势,但是由于内联函数的使用,也会受到一些制约。首先,不能在内联函数中调用另一个inline函数;另外,只能由一个MATLAB表达式组成,并且只能返回一个变量。 创建一个内联函数非常简单,就是使用inline方法,例如: >> f=inline('t^2-3*t-4') f = Inline function: f(t) = t^2-3*t-4 MATLAB会通过检查字符串来推断自变量,例如上面的函数中t就是自变量,如果没有找到,将会使用x作为缺省的自变量,例如常数函数: >> g=inline('3') g = Inline function: g(x) = 3 另外,对于inline也支持多元函数: >> h=inline('x+y') h = Inline function: h(x,y) = x+y

关于javascript事件

A 事件流(event flow ) 事件模型分为两种:冒泡型事件、捕获型事件。 冒泡型(dubbed bubbling )事件:指事件按照从最精确的对象到最不精确的对象的顺序逐一触发。 捕获型(event capturing )事件:它与冒泡型事件相反,指事件按照从最不精确的对象到最精确的对象的顺序逐一触发。 捕获型事件也被称作自顶向下(DOM层次)的事件模型。 由于IE 浏览器不支持捕获型事件,因此并没有被广泛应用。 B 事件监听 i > 通用监听方法 示例一:

给浏览器添加监听方法,分为两种:IE 中的监听方法、标准DOM 的监听方法。 ii > IE 中的监听方法 在IE 浏览器中,每个元素都有两个方法来处理事件的监听。分别是:attachEvent( )和detachEvent( )。 附加事件方法:[object].atta chEvent(“事件名”,方法名); 分离事件方法:[object].detachEvent(“事件名”,方法名); 如:o_p.detachEvent(“onclick”,click_A); 示例:

●使用这种方式可以为同一元素添加多个监听函数; ●在IE 浏览器中,函数的执行顺序与函数的添加顺序相反; ●在IE 浏览器中,虽然函数有先后执行顺序,但都会同时调用; iii > 标准DOM 的监听方法 在使用标准DOM 的浏览器中,每个元素也有两个方法来处理事件的监听。分别是:addEventListener( )和removeEventListener( )。

添加事件监听方法:[object].addEventListener(“事件名”,方法名,事件模型); 移除事件监听方法:[object].removeEventListener(“事件名”,方法名,事件模型); 注意: 这里的“事件名”不能带on ,如:click(如果是onclick 则错误!) “事件模型”为boolean 类型,通常设置为false ,即“冒泡型”事件。(如果是true 则为“捕获型”事件) 示例:

个人心得javascript总结

1、javascript 是一种基于对象,和事件驱动的并具有安全性的脚本语言; 基于对象,动态语言,无需编译,直接解释执行; 2、可以放在的地方; A、中,一对之间; B、单独文件中 C、将脚本程序代码作为属性值、javascript 3、保留字以及关键字; 4、javascript基本语法: 4.1 标识:大小写字母,数字,下划线,和美元符号:不能以数字开头; 4.2 javascript严格区分大小写 4.3 每条语句必须以分号结束;(不写,一般没事,但是可能会引起不必要的歧义) 4.4 多行注释 /* */ 单行注释://

4.5 5、数据类型:(数字,boolean,String字符串;日期什么的是对象了) 特殊值:NaN,Infinity,函数isNaN();isFinite(); Boolean,取值只能是true,和false 全是小写 逻辑运算符

var a=100; var b=0; var c=a||b; alert(c);//返回值是100:就是当两边返回值都是false时,返回第一个或最后一个不为false的值; 6、什么值在javascript中是false? 逻辑运算中,0,“”,false,null,undefined,NaN均表示false 6.1想要赋个默认值:怎么办? function test(e){ e=e||new object(); if(https://www.doczj.com/doc/1d10513451.html,!='ang'){ alert(e);}} test(3); 看这里: Var sth=test;//相当于将函数赋给一个变量,这个变量之后可以传参运行了;Alert(sth(100)); 7、javascript中的系统函数: 7.1 编码解码:alert(encodeURI('sht中午啊'));处理中文情况;decodeURI,对编码的进行解码; 7.2、数值转换; parseInt(‘’);//将其他类型转换成数字;原理:从第一个字符开始,如果第一个可以转换就继续向下走,直到不能转,省略后面,如何第一个都不行,就直接返回NaN格式;

相关主题
文本预览
相关文档 最新文档