正文

js函数的几种写法 闭包概要2013-01-26 15:58:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/edwardguo/54105.html

分享到:

最常见的:

Js代码


Js代码 复制代码 收藏代码
  1. function foo() { 
  2. alert('hi, js'); 
  3. foo(); 



用匿名函数:

Js代码
Js代码 复制代码 收藏代码
  1. var foo = function () { 
  2. alert('hi, js'); 
  3. foo(); 



改装一下,给调用的foo()加个括号:

Js代码


Js代码 复制代码 收藏代码
  1. var foo = function () { 
  2. alert('hi, js'); 
  3. (foo)(); 



干脆,连foo的定义也省掉------把foo赋值语句的等号右边的东东、直接替换掉刚才括起来的foo:

Js代码
Js代码 复制代码 收藏代码
  1. (function () { 
  2. alert('hi, js'); 
  3. })(); 




先看常用的函数:


Js代码 复制代码 收藏代码
  1. function sayHello(name) { 
  2.   var text = 'Hello ' + name; 
  3.   var sayAlert = function() { alert(text); } 
  4.   sayAlert(); 
  5. sayHello('Bob'); 



闭包的例子

一句话描述:

  • 闭包是函数的局部变量,在函数return之后,仍然有值, 或者
  • 闭包是stack-frame,在函数return的时候,它不会被释放。(就好像'stack-frame'是内存分配、而非处于堆栈!)

下面的代码返回一个function的引用:



Js代码 复制代码 收藏代码
  1. function sayHello2(name) { 
  2.   var text = 'Hello ' + name; // local variable 
  3.   var sayAlert = function() { alert(text); } 
  4.   return sayAlert; 
  5. var say2 = sayHello2('Jane'); 
  6. say2(); //hello Jane 




多数JavaScript程序员能够理解上面代码的函数引用如何返回给变量。请在学习闭包之前理解它。C程序员把函数看做返回的一个函数指针,变量sayAlert和say2分别是函数指针。


C函数指针和JavaScript的函数引用有着本质的不同。在JavaScript,函数引用变量既是一个函数指针,又是一个隐藏的闭包指针。


上面代码拥有闭包,因为函数体内又声明了一个匿名函数 function() { alert(text); } ,参看例子中的sayHello2()。如果你在另一个函数内使用function关键字,闭包就产生了。


在C和其他多数语言,当函数return之后,stack-frame就被销毁了,所有的局部变量也就不能访问了。


在JavaScript中,如果你在函数里声明了函数,在你调用的函数renturn之后,局部变量仍然可以访问。请注意上面的例子,我们调用了变量text,它是函数sayHello2的局部变量。


Example 3


这个例子表明局部变量不是拷贝传递,而是引用传递。在外层函数退出时,它把stack-frame保存在内存。



Js代码 复制代码 收藏代码
  1. function say667() { 
  2.   // Local variable that ends up within closure 
  3.   var num = 666; 
  4.   var sayAlert = function() { alert(num); } 
  5.   num++; 
  6.   return sayAlert; 
  7. var sayNumba = say667(); 
  8. sayNumba(); //667,而不是666 
  9. alert(sayNumba.toString()); 



Example 4

三个函数对某个闭包使用同一个引用,因为它们均在setupSomeGlobals()里声明的。


Js代码 复制代码 收藏代码
  1. var gAlertNumber = gIncreaseNumber = gSetNumber = null
  2. function setupSomeGlobals() { 
  3.   // Local variable that ends up within closure 
  4.   var num = 666; 
  5.   // Store some references to functions as global variables 
  6.   gAlertNumber = function() { alert(num); } 
  7.   gIncreaseNumber = function() { num++; } 
  8.   gSetNumber = function(x) { num = x; } 
  9. setupSomeGlobals(); 
  10. //任意、多次 运行下面的函数 
  11. gAlertNumber(); 
  12. gIncreaseNumber(); 
  13. gSetNumber(5); //把num重新设为 5 
  14. gSetNumber(-8888); //把num重新设为 -8888 



重新运行setupSomeGlobals(); 就会重新产生一个新的闭包。在JavaScript中,当你在函数里又声明一个函数,外部函数每调用一次,内部函数将再被重新产生一次。


Example 5


当心下面例子的循环:闭包中的局部变量可能和你最初想的不一样。


Js代码 复制代码 收藏代码
  1. function buildList(list) { 
  2.   var result = []; 
  3.   for (var i = 0; i < list.length; i++) { 
  4.     var item = 'item' + list[i]; 
  5.     result.push( function() {alert(item + ' ' + list[i])} ); 
  6.   } 
  7.   return result; 
  8.  
  9. function testList() { 
  10.   var fnlist = buildList([1,2,3]); 
  11.   // using j only to help prevent confusion - could use i 
  12.   for (var j = 0; j < fnlist.length; j++) { 
  13.     fnlist[j](); 
  14.   } 
  15.  
  16. testList();  //输出3次:'item3 undefined' 



Example 6


下面的例子表明,闭包包含了 在外部函数退出之前、定义的任何局部变量。注意,变量alice实际上在匿名函数之后声明的。匿名函数先被声明:当函数被调用时,它可以访问alice,因为alice在闭包里。

Js代码 复制代码 收藏代码
  1. function sayAlice() { 
  2.   var sayAlert = function() { alert(alice); } 
  3.   // Local variable that ends up within closure 
  4.   var alice = 'Hello Alice'
  5.   return sayAlert; 
  6. sayAlice()(); //Hello Alice 
  7. alert(alice); //错误:alice不是全局变量,它在函数体内var了 



Example 7


下面的例子表明,每次调用会产生各自的闭包。

Js代码 复制代码 收藏代码
  1. function newClosure(someNum, someRef) { 
  2.   // Local variables that end up within closure 
  3.   var num = someNum; 
  4.   var anArray = [1,2,3]; 
  5.   var ref = someRef; 
  6.   return function(x) { 
  7.       num += x; 
  8.       anArray.push(num); 
  9.       alert('num: ' + num +  
  10.           '\nanArray ' + anArray.toString() +  
  11.           '\nref.someVar ' + ref.someVar); 
  12.     } 
  13. closure1 = newClosure(40, {someVar : 'closure 1'});  
  14. closure1(5); 
  15.  
  16. closure2 = newClosure(1000, {someVar : 'closure 2'}); 
  17. closure2(-10); 


小结


读一些说明要比理解上面的例子难得多。我对于闭包的说明以及stack-frame等等在技术上可能不正确 --- 但是它们的确有助于理解

阅读(2495) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册