代码改变世界

javascript闭包

2012-08-28 00:45  youxin  阅读(185)  评论(0编辑  收藏  举报

ecmascript最让人误解的一点是他支持闭包。所谓闭包,是指词法表示包括不必计算的变量的函数。也就是说,该函数能使用函数外定义的变量。在ecmascript中使用全局变量时一个简单的闭包实例:

var sMessage="hello world";
function sayHelloWorld(){
    alert(sMessage);
}

sayhelloworld();

会输出helloworld。

在一个函数中定义另外一个函数会使闭包更复杂。

var iBaseNum=10;
function addNumbers(iNum1,iNum2){
    function doAddition(){
        return iNum1+iNum2+iBaseNum;
    }
    return doAddtion();
}

这里,函数addNumbers()包括函数doAddtion()(闭包),内部函数是个闭包,因为它将获取外部函数的参数inum1,inum2和全局变量ibaseNum的值。addNUmber()最后一步调用了内部函数,这里要掌握的重要概念是doAddtion()函数根本不接受参数,它使用的值是从执行环境中获取的

另一篇文章:http://www.cnblogs.com/hh54188/archive/2012/03/01/2374921.html

函数作为返回值

在函数中可以有返回值,但是我们一般都熟悉数值的返回,但你一旦意识到函数只是一种数据的话,你就可以想到同样可以返回函数。注意看下面这个函数:

function a() {

  alert('A!');

  return function(){

    alert('B!');

  };

}

它返回了一个弹出”B!”的函数。接下来使用它:

var newFunc = a();
newFunc();

结果是什么呢?首先执行a()的时候,弹出”A!”,此时newFunc接受了a的返回值,一个函数——此时newFunc就变成了那个被a返回的函数,再执行newFunc时,弹出”B!”

avascript的作用域

javascript的作用域很特别,它是以函数为单位的,而不是像其他语言以块为单位(如一个循环中),看下面这个例子:

var a = 1; function f(){var b = 1; return a;}

 

如果你此时试图想得到b的值:在firebug中试图输入alert(b)的话,你会得到错误提示:

b is not defined

为什么你可以这么理解:你所在的编程环境或者窗口是最顶级的一个函数,好像一个宇宙,但是b只是在你内部函数的一个变量,宇宙中的小星球上的一个点,你很难找到它,所以在这个环境中你不能调用它的;反之这个内部函数可以调用变量a,因为它暴露在整个宇宙中,无处藏身,同时也可以调用b,因为它就在自己的星球上,函数内部。

就上面这个例子说:

  1. 在f()外,a可见,b不可见
  2. 在f()内,a可见,b也可见

再复杂点:

var a = 1; //b,c在这一层都不可见

function f(){

  var b = 1;

  function n() { //a,b,c对这个n函数都可以调用,因为a,b暴露在外,c又是自己内部的

    var c = 3;

  }

}

问你,函数b可以调用变量c吗?不行,记住javascript的作用域是以函数为单位的,c在n的内部,所以对f来说是不可见的。

开始正式谈闭包:

首先看这个图:

假设G,F,N 分别代表三个层次的函数,层次如图所示,a,b,c分别是其中的变量。根据上面谈到的作用域,我们有如下结论:

  1. 如果你在a点,你是不可以引用b的,因为b对你是不可见的
  2. 只有c可以引用b

闭包的吊诡之处的就在于发生了如下情况:

N突破了F的限制!跑到于a同一层了!因为函数只认它们在定义时所处的环境而不是执行时,这点很重要),N中的c仍然可以访问b!此时的a还是不可以访问b!

但是这是怎么实现的呢?如下:

function f(){

  var b = "b";

  return function(){ //没有名字的函数,所以是匿名函数

    return b;

  }

}

注意返回的函数可以访问它父亲函数中的变量b

此时如果你想取b的值,当然是undefined

但是如果你这么做:

var n = f();

n();

你可以取到b的值了!虽然此时n函数在f的外面,b又属于f内部的变量,但是f内部出了一个内鬼,返回了b的值……

闭包2

var n;

function f(){

  var b = "b";

  n = function(){

    return b;

  }

}

如果此时调用f会怎么样?那就生成了一个n的全局范围函数,但是它却能访问f的内部,照样返回b的值,与上面有异曲同工之妙!

闭包3:

你还可以用闭包访问函数的参数

function f(arg) {

  var n = function(){

    return arg;

  };

  arg++;

  return n;

}

此时如果使用:

var m = f(123);

m();

 

结果是124

因为此时f中返回的匿名函数经过了两道转手,先给n,再赋给外面的m,但本质没有变,把定义时父函数的参数返回了

闭包4

var getValue, setValue;

function() {

  var secret = 0;

  getValue = function(){

    return secret;

  };

  setValue = function(v){

    secret = v;

  };

})
运行如下:getValue()

0

setValue(123)

getValue()

123

这里的getValue和setValue就类似于一个对象的属性访问器 来自;http://www.cnblogs.com/hh54188/archive/2012/03/01/2374921.html

 

http://www.cnblogs.com/TomXu/archive/2012/01/31/2330252.html