正文

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

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

分享到:

最常见的: Js代码 Js代码 function foo() {  alert('hi, js');  }  foo();  function foo() { alert('hi, js'); } foo(); 用匿名函数: Js代码 Js代码 var foo = function () {  alert('hi, js');  }  foo();  var foo = function () { alert('hi, js'); } foo(); 改装一下,给调用的foo()加个括号: Js代码 Js代码 var foo = function () {  alert('hi, js');  }  (foo)();  var foo = function () { alert('hi, js'); } (foo)(); 干脆,连foo的定义也省掉------把foo赋值语句的等号右边的东东、直接替换掉刚才括起来的foo: Js代码 Js代码 (function () {  alert('hi, js');  })();  (function () { alert('hi, js'); })(); 先看常用的函数: Js代码 function sayHello(name) {    var text = 'Hello ' + name;    var sayAlert = function() { alert(text); }    sayAlert();  }  sayHello('Bob');  function sayHello(name) { var text = 'Hello ' + name; var sayAlert = function() { alert(text); } sayAlert(); } sayHello('Bob'); 闭包的例子 一句话描述: 闭包是函数的局部变量,在函数return之后,仍然有值, 或者 闭包是stack-frame,在函数return的时候,它不会被释放。(就好像'stack-frame'是内存分配、而非处于堆栈!) 下面的代码返回一个function的引用: Js代码 function sayHello2(name) {    var text = 'Hello ' + name; // local variable    var sayAlert = function() { alert(text); }    return sayAlert;  }  var say2 = sayHello2('Jane');  say2(); //hello Jane  function sayHello2(name) { var text = 'Hello ' + name; // local variable var sayAlert = function() { alert(text); } return sayAlert; } var say2 = sayHello2('Jane'); 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代码 function say667() {    // Local variable that ends up within closure    var num = 666;    var sayAlert = function() { alert(num); }    num++;    return sayAlert;  }  var sayNumba = say667();  sayNumba(); //667,而不是666  alert(sayNumba.toString());  function say667() { // Local variable that ends up within closure var num = 666; var sayAlert = function() { alert(num); } num++; return sayAlert; } var sayNumba = say667(); sayNumba(); //667,而不是666 alert(sayNumba.toString()); Example 4 三个函数对某个闭包使用同一个引用,因为它们均在setupSomeGlobals()里声明的。 Js代码 var gAlertNumber = gIncreaseNumber = gSetNumber = null;  function setupSomeGlobals() {    // Local variable that ends up within closure    var num = 666;    // Store some references to functions as global variables    gAlertNumber = function() { alert(num); }    gIncreaseNumber = function() { num++; }    gSetNumber = function(x) { num = x; }  }  setupSomeGlobals();  //任意、多次 运行下面的函数  gAlertNumber();  gIncreaseNumber();  gSetNumber(5); //把num重新设为 5  gSetNumber(-8888); //把num重新设为 -8888  var gAlertNumber = gIncreaseNumber = gSetNumber = null; function setupSomeGlobals() { // Local variable that ends up within closure var num = 666; // Store some references to functions as global variables gAlertNumber = function() { alert(num); } gIncreaseNumber = function() { num++; } gSetNumber = function(x) { num = x; } } setupSomeGlobals(); //任意、多次 运行下面的函数 gAlertNumber(); gIncreaseNumber(); gSetNumber(5); //把num重新设为 5 gSetNumber(-8888); //把num重新设为 -8888 重新运行setupSomeGlobals(); 就会重新产生一个新的闭包。在JavaScript中,当你在函数里又声明一个函数,外部函数每调用一次,内部函数将再被重新产生一次。 Example 5 当心下面例子的循环:闭包中的局部变量可能和你最初想的不一样。 Js代码 function buildList(list) {    var result = [];    for (var i = 0; i < list.length; i++) {      var item = 'item' + list[i];      result.push( function() {alert(item + ' ' + list[i])} );    }    return result;  }    function testList() {    var fnlist = buildList([1,2,3]);    // using j only to help prevent confusion - could use i    for (var j = 0; j < fnlist.length; j++) {      fnlist[j]();    }  }    testList();  //输出3次:'item3 undefined'  function buildList(list) { var result = []; for (var i = 0; i < list.length; i++) { var item = 'item' + list[i]; result.push( function() {alert(item + ' ' + list[i])} ); } return result; } function testList() { var fnlist = buildList([1,2,3]); // using j only to help prevent confusion - could use i for (var j = 0; j < fnlist.length; j++) { fnlist[j](); } } testList(); //输出3次:'item3 undefined' Example 6 下面的例子表明,闭包包含了 在外部函数退出之前、定义的任何局部变量。注意,变量alice实际上在匿名函数之后声明的。匿名函数先被声明:当函数被调用时,它可以访问alice,因为alice在闭包里。 Js代码 function sayAlice() {    var sayAlert = function() { alert(alice); }    // Local variable that ends up within closure    var alice = 'Hello Alice';    return sayAlert;  }  sayAlice()(); //Hello Alice  alert(alice); //错误:alice不是全局变量,它在函数体内var了  function sayAlice() { var sayAlert = function() { alert(alice); } // Local variable that ends up within closure var alice = 'Hello Alice'; return sayAlert; } sayAlice()(); //Hello Alice alert(alice); //错误:alice不是全局变量,它在函数体内var了 Example 7 下面的例子表明,每次调用会产生各自的闭包。 Js代码 function newClosure(someNum, someRef) {    // Local variables that end up within closure    var num = someNum;    var anArray = [1,2,3];    var ref = someRef;    return function(x) {        num += x;        anArray.push(num);        alert('num: ' + num +             '\nanArray ' + anArray.toString() +             '\nref.someVar ' + ref.someVar);      }  }  closure1 = newClosure(40, {someVar : 'closure 1'});   closure1(5);    closure2 = newClosure(1000, {someVar : 'closure 2'});  closure2(-10);  function newClosure(someNum, someRef) { // Local variables that end up within closure var num = someNum; var anArray = [1,2,3]; var ref = someRef; return function(x) { num += x; anArray.push(num); alert('num: ' + num + '\nanArray ' + anArray.toString() + '\nref.someVar ' + ref.someVar); } } closure1 = newClosure(40, {someVar : 'closure 1'}); closure1(5); closure2 = newClosure(1000, {someVar : 'closure 2'}); closure2(-10); 小结 读一些说明要比理解上面的例子难得多。我对于闭包的说明以及stack-frame等等在技术上可能不正确 --- 但是它们的确有助于理解

阅读(3467) | 评论(1)


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

评论

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