JavaScript闭包,什么是闭包,对闭包的理解

【Ranger】mac下Apache Ranger编译安装 a、编译过程中出现测试用例不通过和文件认证错误错误:带上参数-DskipTests=true -Drat.skip=true 重新编译;b、若编译过程中出现缺少jar包的情况,可能下载不了,需要手动自动添加;c、编译所需的其他工具如maven等安装配置略。采用这个会报错,因此我才用了下面一个命令。初始化设置Ranger Admin:执行。然后进入target目录。 阅读详情
阮一峰的网络日志  » 首页  » 档案

分类:

 

学习Javascript闭包(Closure)

作者: 阮一峰

日期: 2009年8月30日

珠峰培训

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

  var n=999;

  function f1(){
    alert(n);
  }

  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

  function f1(){
    var n=999;
  }

  alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

  function f1(){
    n=999;
  }

  f1();

  alert(n); // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

  function f1(){

    var n=999;

    function f2(){
      alert(n); // 999
    }

  }

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

  function f1(){

    var n=999;

    function f2(){
      alert(n); 
    }

    return f2;

  }

  var result=f1();

  result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。

  function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());


代码片段二。

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()());

(完)

一灯学堂

QCon 北京2018

相关文章

留言(121条)

讲的很清楚明了,连我都懂了,要是我们大学时的老师也能这么讲课。。。他们只会放幻灯片

这里有个 PPT 用于说明 JS 闭包,说明得很透彻: http://www.gracecode.com/archives/2385/

呵呵,可以作为面试题了!

闭包个人感觉是一种描述函数内部的数据结构,来描述函数的运行上下文.Javascript编程精粹 这本书算是讲的比较好一点.

类是有行为的数据,闭包是有数据的行为。

阮兄:
有点疑问:
function f1(){

    n=999;

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999
可以写成如下的不也一样么?

function f1(){

    n=999;

    return n;

  }
var result=f1();
alert(result);

@tt 实际上后种方法每次调用 f1 时,都会声明 n = 999,而且 n 无法保留状态值(严格按照你的代码,其实 n 为全局变量,我理解你的本意为 var n = 999;)。

而第一种 f1 实际上返回的是个匿名函数,这样 n 作用域被另外个 f2 函数作用域所使用,因此它会保留。n 不会被重复声明,且内容会被保存

这是我见过最简单易懂的闭包教程。

支持下。

博主的博客写的不错,简单易懂,东西涉及的很多方面我都有兴趣,看来是同道中人,^_^

一文中的!!!!!!!!!!!!
学习了!!

想知道思考题的答案,
我以为是:My Object

顶楼主,我读了一些文章。不是特明白。
有个问题。
记得有人说。外面的函数是closure,
好像楼主说里面的函数是closure.

不知道到底哪个是?谢谢。

楼主讲讲最后一个思考题,没明白

请版主讲一讲最后一个例子怎么回事,没有看明白

函数中的this一般是指向window中的变量。

引用hou的发言:
请版主讲一讲最后一个例子怎么回事,没有看明白

上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。

如果非要指向object,可显式的控制--把代码的最后一句改为 alert(object.getName().call(object));

阮大哥讲的很透彻 受益匪浅

大道至简,给予我这个初学者很大的帮助,谢谢!

浅显易懂,很好。

如下看法,认为有待商榷:
#1、有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

#2、这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
//如果 #1 说法正确,下句会打印10,实际结果是test未定义。
//alert(test); // error test 未定义
  
//如果 #2 正确,语句 nAdd(); 位置在何处应该都能执行,测试结果在下面这个位置,也就是语句 var result=f1(); 前。是不能执行的。
//nAdd();
var result=f1();
result(); // 999
  nAdd();
result(); // 1000

To 过客:

函数内部定义的方法和变量,要等到函数执行过以后,才会真正定义

但是从过客说的里面可以引出另外的问题,当使用这样的代码时。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }

如果在函数f1定义之前添加变量定义

var n = 1;
然后调用
f1()();
则显示为999。说明nAdd中的n确实是作为全局变量存在。于是问题就来了——有什么方法让他可以是父函数中定义的n呢?

大道至简,很不错!~ 这篇文章我要转了...

引用George Wing的发言:

函数中的this一般是指向window中的变量。

this关键字代表的实例会根据环境不同而变化的. 他总是指向owner 看看这篇你大概就动this这个关键字了

http://www.quirksmode.org/js/this.html

最后一个题感觉和闭包没什么关系啊,能详细解释一下吗?因为当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象,这在《Javascript权威指南》上说的很清楚,所以答案肯定是“The Window”,和闭包没什么关系啊

最后一题重点在this

如果把f2申明成全局变量,道理一样吗?

太经典了!
终于理解了,一箭双雕啊!既理解了this的用法,又理解了闭包

这个例子很不错,真的是一箭双雕

前面讲得挺好的,浅显易懂。对最后的两个例子搞不清楚为啥。版主能不能具体分析下。
var obj=function()
{
var MyFunc=function()
{
alert("hello world");
}
return function()
{
return MyFunc;
}
}()
var f3=obj();
var f4=obj();
alert(f3 === f4);//为啥是TRUE;搞不懂

最后两个例子很精炼 ^ ^

尝试解答代码段一:
getNameFunc: function() {//假设函数名为A
return function()/*假设函数名为B*/ { return this.name; };
}
在函数里面构建函数的时候,闭包产生。
在函数B内调用函数A的this.name,由于函数A没有name属性,所以就去找全局变量name,找到了,所以返回“The Window”,要是没有找到,则返回“undefined”。

代码段二可以尝试将代码更改为:
var _this = this;
return function() { return _this.name +"__"+ this.name; };

只有一点没弄懂,如下代码,nAdd在函数外为什么可以有意义?而test不行?想了好久,不知道那里有解答
  function f1(){
test=10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }

通俗易懂,, 阅览无数教程, 看了这篇, 终于明白了点.

写得太好了

这篇文章是阮兄一贯的风格,我喜欢,不过 "Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。"这句有点奇怪,c不一样可以在函数内部直接读取全局变量么?难道不是么?

阮大哥能不能具体讲下最后的思考题啊? 感觉关键在this

变量的作用域无非就是两种:全局变量和局部变量。
这句话值得商榷, 变量的作用域确实只有两种, 不过他们是全局对象和函数.
你想说的或许是变量的类型有两种?

理解最后两个例子:

1 函数中的this指的是调用这个函数的owner
2 object.getNameFunc()是返回一个函数,并没有执行函数中的代码
3 增加一个例子0:

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
return (this.name);
      }
  };
var name = object.getNameFunc();
  alert(name); 

4 把例子1变成

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name; //这个this是有上下文的限制的
      };
    }
  };
var tmp = Object.getNameFunc(); //此时没有执行this.name
var name = tmp();//这个时候才执行,这时候的this上下文为全局
alert(name);
//alert(object.getNameFunc()())

5 把例子2变成:

var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
var tmp = Object.getNameFunc(); //这个时候执行了that = this,这里的this上下文是object,所以that指的是object
var name = Object.getNameFunc(); //这个时候执行了that.name
alert(name);
//alert(object.getNameFunc()()); 

引用Jason的发言:

但是从过客说的里面可以引出另外的问题,当使用这样的代码时。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }

如果在函数f1定义之前添加变量定义var n = 1;然后调用f1()();则显示为999。说明nAdd中的n确实是作为全局变量存在。于是问题就来了——有什么方法让他可以是父函数中定义的n呢?

var n = 1;
function f1(){
	var n = 999;
	nAdd = function(){
		n++;
	}
	function f2(){
		alert(n);
	}
	return f2;
}
var b = f1();
nAdd();//n = 999+1 = 1000
b();//弹出 n 的值是 1000 (闭包内的变量n)
alert(n);//弹出n的值是 1 (全局)
全局的函数 nAdd 和 由f1返回的函数中 所使用到的变量n全部为f1函数内的局部变量n,而不是全局变量n,证据就是上面的代码中最后一句 alert(n) 弹出的值是1, 也就是说 nAdd中的n++并没有改变全局变量中n的值.

你自己描述的是 f1()() 显示的是999,说明 n 是使用的f1内部的变量n,而非是全局变量n,不知道你为什么会有

说明nAdd中的n确实是作为全局变量存在。
这种想法呢? 如果想在nAdd中使用全局变量n(即在函数外面定义的n)的话,使用window.n来访问.

楼主文章中的:


二、如何从外部读取局部变量?

这一整大段中的
n=999;

根据整篇文章所表达的内容,应该为:
var n=999;

因为如果没有加var,则声明的是全局变量,既然是全局变量,则在所有函数内部都是可见的,也就不会存在闭包这种说法.

请求楼主修正.

引用小彘的发言:

前面讲得挺好的,浅显易懂。对最后的两个例子搞不清楚为啥。版主能不能具体分析下。
var obj=function()
{
var MyFunc=function()
{
alert("hello world");
}
return function()
{
return MyFunc;
}
}()
var f3=obj();
var f4=obj();
alert(f3 === f4);//为啥是TRUE;搞不懂

因为f3和f4都指向同一个地址(即MyFunc).


var obj = (function() {
var MyFunc=function() {
alert("hello world");
}
return function() {
return MyFunc;
}
})();
var f3=obj();
var f4=obj();
alert(f3 === f4);//为啥是TRUE;搞不懂

我测试了一下,为什么第一个例子输出的什么都没有是null,第二个我理解是myobject。谁能解释下

引用小秦的发言:

请求楼主修正.

谢谢指出,已更正。

起初以为函数内用var声明变量,就等于用了this声明,其实不是
var w=100;
function f1(){
//var w=101;
//this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:100

var w=100;
function f1(){
var w=101;
//this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:100

var w=100;
function f1(){
w=101;
//this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:101

var w=100;
function f1(){
//var w=101;
this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:102

看起来函数中的var和this并不是一个概念,函数内的局部变量与函数的属性不是一回事,不过通过上面的情况能够加深理解this和闭包

很不错的讲解,楼主写的通俗易懂,很棒的理解,很受用!我的qq:290913917 希望有机会成为共同研究javascript和html5的伙伴,谢谢!

我感觉第一个思考题是不是这样理解:
首先this指向的是当前运行该函数的对象,
1、object.getNameFunc()得到了一个函数,函数为function(){return this.name}
2、object.getNameFunc()(),此时为window运行该函数,所以this指向的是window,所以this.name为The window

做习题之前有一点需要很清楚:

内部函数可以访问定义它们的外部函数的参数和变量(除了this和arguments之外)
如果需要访问对象的name属性的话,就需要显示的定义一个变量that来引用this,而这个变量此时就指向object对象了。

第一题改成下面这样就很清楚了。getNameFunc的第一个()是属于方法调用,所以this绑定到了object对象,自然this.name为"My Object",但是闭包函数无法访问这个this,它只能访问到全局的this。

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
alert(this.name);
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());

写的真不错。。。看了很多文章讲闭包都是云里雾里的。。看了本文才恍然大悟。。。哦原来闭包如此简单。。。。楼主写的不错。。。

前面讲的我都明白,但是最后两个例子还是不明白,好多处都不懂!
1. var object = {。。。} 这是在干什么?是在声明一个变量?还是在声明一个类,然后里面有许多属性?

2 . object.getNameFunc()(); 怎么会有两个括号?


3. 如何判断 this指向的是object 对象还是全局对象 ?

闭包是运行时中的概念,不能讲哪个函数是一个闭包!而是哪个函数在运行时存在一个闭包!有时候,好几个函数都可以组成一个闭包呢:
function ff()
{
var local=1;
this.add1=function()
{
return ++local;
};
this.add2=function()
{
return ++local;
}
}

var f=new ff();

alert(f.add1());//2
alert(f.add2());//3

最后两个例子中,第一个其实不是闭包,第二个是,但第二个例子其实不用那么复杂,直接把第一个例子中的this去掉就可以了。

为什么第一个运行以后结果是result?!既不是window也不是object....???

 function f1(){
    n=999;
  }

  alert(n); // error

这段代码在IE8和FIREFOX5上根本不能运行,求解释...

@eva 
function f1(){
    n=999;
  }

  alert(n); // error
很明显啊,全局变量n是在函数f1中定义的,你不调用函数f1,n怎么定义呢
function f1(){
    n=999;
  }
f1();
  alert(n);
这样不就OK了

At this time enhancements in could also be noticed in a point of contention.

思考题中的例子貌似是 javascript高级程序设计里的。今天刚看到。

你真是个有趣的人,为什么我总能在你这里找到我感兴趣的博文?……

楼主可以解释一下思考题一吗?我看很多人跟我一样都不是很懂思考题一啊,万分感谢!

引用Legend1988的发言:

楼主可以解释一下思考题一吗?我看很多人跟我一样都不是很懂思考题一啊,万分感谢!

同问,为什么this在嵌套函数中的意义不一样

this始终表示调用者的应用,第一个的闭包返回出来的一个函数,就是在window的环境下调用了这个函数,所以这个this是指向的window,而第二个把this保存在了that中。不知道说清楚没有

不错,小伙子讲的很到位,比一些书上生硬的翻译要好一些。Good!

后面第1个例子怎么输出result, result 是什么意思

@陈锐达:

根据您的解释,运行结果是不对的!如在A中定义name,执行结果一样

实际上,我认为闭包只是给外部函数提供了一个操作局部变量的途径,局部变量本身并没有改变,仍然为局部变量。

我也觉得最后两个例子,好像跟this的关系更大……

@tt 发问需谨慎, 文中的写法是一种类的写法, 域里有动作,你这个是函数。

渐渐地对闭包和this有点了解,尤其加上各位网友的激情讨论,并附上示例,通俗易懂!

引用Joe的发言:
最后两个例子中,第一个其实不是闭包,第二个是,但第二个例子其实不用那么复杂,直接把第一个例子中的this去掉就可以了。

不行哦,一定要引用一次,不然还不是闭包。

引用apple的发言:

this始终表示调用者的应用,第一个的闭包返回出来的一个函数,就是在window的环境下调用了这个函数,所以这个this是指向的window,而第二个把this保存在了that中。不知道说清楚没有

我赞成。。

个人觉着楼主说的不是闭包

初学者就这么理解闭包,最好不过了。

思考题答案:The Window、My Object;其实最关键的就是要明白作用域链和闭包所起到的作用,其实闭包说到底就是一个函数,而且函数调用返回后其资源所占用的栈区并没有释放,,所以变量就还保存在内存中,由于作用域链的关系,它会去寻找离其最近的var声明,var声明所在就是该闭包所在的层,从而在这层里面所得到的结果就是它最后的值,于是乎返回值也就是这个最终的值了

最后两道思考题~ 其实和函数调用还有关系的~ 在以上例子中使用的是函数调用的方式,this这时候是指全局变量

引用afity的发言:

最后一题重点在this

正解,和闭包有什么关系啊

引用红雨的发言:

正解,和闭包有什么关系啊

对于代码片段一

object.getnameFunc() 返回的匿名闭包函数被全局变量所引用,其中的this指向

全局变量,当执行时打印The Window 。

对于代码片段二

object.getnameFunc() 在返回闭包函数前,将this赋给that,此时getnameFunc是由

object调用的,故而this指向object,当内部函数被返回时,由于闭包的特性,仍然

能访问到外部函数中的值,当执行打印My Object 。

代码段一、
当一个函数作为函数而不是方法调用的时候,这个this关键字引用全局对象。容易令人混淆的是,当一个嵌套的函数(作为函数)在一个包含的函数中调用,而这个包含的函数是作为方法调用的,这也是成立的:this关键字在包含的函数中有一个值,但是它却(不太直观地)引用嵌套的函数体的内部的全局对象。
所以第一个打印出来的是"The Window"
代码段二、
由于this关键字不是在包含的函数中引用的,而是通过that=this这个调用的,所以这个this不是在闭包内的,因此这个this就不能调用函数体内的全局对象,而是他的局部对象object.name,所以第二个打印出来的是"My Object"

说多无用,关键是理清函数什么时候作为对象使用,什么时候作为函数使用。

object.getnameFunc()() 也可以改为object.getnameFunc().call()
这就是javascript狡猾的地方。

讲得很易懂 ··· 然后,最后思考题 感觉 是this关键字的问题,暂时还不懂··

谢谢,关于闭包本身的概念非常清晰, 不过我当初读你这篇文章的时候最大的困惑是为什么要搞出闭包这个东西来, 我这里写了我的理解

http://www.hetaoblog.com/myblogs/post/javascript-closure-chain-scope-anonymous-function-module.jhtml

请问阮兄/各位高人,假如某个JavaScript的函数对象已被调用过一次,如何用代码验证/判断当该函数对象被第二次调用时,它是新创建的还是使用的内存中已有的?

引用tomwang的发言:
最后一个题感觉和闭包没什么关系啊,能详细解释一下吗?因为当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象,这在《Javascript权威指南》上说的很清楚,所以答案肯定是“The Window”,和闭包没什么关系啊

完全赞同这位仁兄的看法!!前面闭包讲的不错,但是最后面的思考题出的很烂啊,跟闭包没关系,让人看完了反而糊涂了!

有个特别大的疑问:

……原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,……

f2真的被赋给一个全局变量了?

引用hanvslin的发言:

完全赞同这位仁兄的看法!!前面闭包讲的不错,但是最后面的思考题出的很烂啊,跟闭包没关系,让人看完了反而糊涂了!

最初我也以为思考题与文章主题无关,这两天在反复看 JavaScript 权威指南 函数一章,都看晕了...
产生闭包效果的环境必须是嵌套函数的引用被保存到了一个全局作用域里面,也不难理解 阮老师思考题的设计了

在退出函数之前,将不使用的局部变量全部删除。

请教一下这个改如何做?不太明白。。。Thanks!

保留内存值的解释有点不好,即使var result = f1(); 即使这里不赋值给全局变量result,通过f1()();也不会改变n的值,呵呵~

后面的思考题 阮哥能解释一下吗 
前面的例子是看懂了 但是思考题还是不会做

引用SpiderMan的发言:

感觉这里的例子更好一些 https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Closures

这里对于闭包的讲解好一点:普通的函数内嵌,内部函数是先执行;而闭包则是:先把内部函数赋给外部函数,然后在执行。

跟阮老师学JS!

感觉应该从js作用域链及其原理来分析闭包,这样才能彻头彻尾明白!

引用George Wing的发言:

上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。

这里说的this才是正确的。如果将此处的this能够轻松的理解,我想本文的最后一道题就懂了。你怎样认为呢?

每个函数在被调用时,其活动对象都会自动取得两个特殊变量:this和arguments。内部函数在搜索这个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量(这一点通过前面的图可以看得更清楚)。意思就是说找到匿名函数中的this和arguments就不会再往下找了(这里的往下指的是外层的包含函数,和最外层的window全局环境),而匿名函数的this对象通常指向window,所以输出的是全局的那个字符串。不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了

不执行调用f1肯定不可能生成test变量,第二个问题同样的原因。


引用过客的发言:

浅显易懂,很好。

如下看法,认为有待商榷:
#1、有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

#2、这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
//如果 #1 说法正确,下句会打印10,实际结果是test未定义。
//alert(test);// error test 未定义
  
//如果 #2 正确,语句 nAdd(); 位置在何处应该都能执行,测试结果在下面这个位置,也就是语句 var result=f1(); 前。是不能执行的。
//nAdd();
var result=f1();
result(); // 999
  nAdd();
result(); // 1000

引用George Wing的发言:

上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。

哦。看了你这个解释就了解了

说的很易懂,最后两个例子还是有点模糊

为什么话要反着说呢,应该说正例,这着用太糟糕了,赞同 @迷途小书童 @steven

引用tomwang的发言:

最后一个题感觉和闭包没什么关系啊,能详细解释一下吗?因为当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象,这在《Javascript权威指南》上说的很清楚,所以答案肯定是“The Window”,和闭包没什么关系啊

《Javascript权威指南》上说:如果嵌套函数作为函数调用,其this值不是全局对象(非严格模式下)就是undefined(严格模式下); 如果嵌套函数作为方法调用,其this值指向调用它的对象。所以代码片段一,getNameFunc()作为object的方法,所以this值应该指向调用它的对象(object),而object自己定义name为"My Object",所以片段一,我觉得应该是弹出"My Object"。我是新手,我只是从this方向对这个函数分析,有错误的地方,还望高手指点。

“闭包的概念”这一节总结的非常好,浅显易懂。同时,也了解了闭包的两个用处:一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

最后两个例子关键是区分object.getnameFunc()调用时和调用后的this指向。
第一个问题,object.getnameFunc()()函数在执行时this属于全局域,因此结果是the window
第二个问题,通过使用that=this 保留了在调用object.getnameFunc()时的this状态值。因此在getnameFunc()的闭包中访问的变量是已经不是this的了,而是that的~

JS新手,学习了,思考题和讨论很强大。

思考题解答(个人见解):
1、因为闭包最后的返回值是一个函数,注意紧紧是一个函数而已 并没有执行,等到alert调用时才执行,而这时执行调用的方法,前面阮老师说了,函数内没有var声明的事全局变量,所以调用的getName是一个全局的变量,所以对应this找到的是全局的name.
2、因为this的对象引用在编译时就已经确定了,就是object,所以返回值在Object中开始查找,找到了Obeject中的name就不到全局变量中查找。

综合各种理解之后,我明白最后的“代码片段一”中的闭包函数中的this是window对象,也就是说..闭包函数的范围竟然是window。。。

这么理解还不如不理解,这样下来对新手是一种误导。所以说才建议大家尽量都去看英文网站。唉

其实看完这篇文章,对于闭包的概念就有了更深刻的理解
最后留的两道题目,很好的说明了这一点。
因为第一题中getNameFunc这个方法或者叫函数是属于全局作用域的,所以里面返回的this始终都是指向window的。而第二题中用that=this改变了当前函数指向的作用域,所以第二题中的this最终只想的是myobject。
不知道我的理解正确不正确。
如果说错,请勿见怪...

return function() {
return this.name;
}
这里的this代表调用方法时所在的的作用域:全局作用域window。

return function() {
return that.name;
}
object.getNameFunc()()此处实现了从外部调用局部变量的方法,that会顺着作用域链向上级作用域查找,所以获得是getnameFunc的定义的变量var that = this。

@小彘:

是引用类型。f3和f4的值是指针,只想obj()。所以全等是true。

后两个应该this的作用域问题,不是闭包的问题吧。 弄的我都糊涂了... 还好找了一篇通俗的问题在,终于弄懂了

执行过f1这个函数后,test如果是局部变量会被销毁,如果是全局变量则会保存在内存堆(heap)里,如果不执行f1函数,test和nadd都是不存在的

不,我补充一下,我应该是说错了,既然f2函数是闭包,那么f2函数会保持它的外部函数f1的作用域,即使定义test为f1函数的局部变量(var test = 10);那么也要先检查f2是否对test产生引用,如果引用数为0,则在f1()调用完后销毁,再运行f1()()(实际上是调用f2函数)也不会产生对test这个局部变量的引用,所以它就在栈中被销毁了。
如果理解的不对,请大侠们拍砖

最后的思考题如果能理解这句话“this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的”,我想就能它们的运行结果了

this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。喜欢这句话,但是闭包还是没有理解透彻。

我觉得大家说了这么多,都没人把代码写出来运行一下来验证自己的答案么,也不管自己的答案是否正确么。通过运行发现:
思考题一:打印:空白
思考题二:打印:My Object
虽然我不太了解,但是评论中的很多人自己也理解错误了。

R兄講的非常簡單易懂。

我觉得是这样的,
第一个里边的this指向的是那个闭包函数,
第二个例子里边的this指向的是object。

引用陈守川的发言:

我觉得大家说了这么多,都没人把代码写出来运行一下来验证自己的答案么,也不管自己的答案是否正确么。通过运行发现:
思考题一:打印:空白
思考题二:打印:My Object
虽然我不太了解,但是评论中的很多人自己也理解错误了。

第一个 打印结果为 The window
第二个 打印结果为 My Object

第一个 this为全局对象,所以alert处理的name为The window
第二个 that 为object对象,所以alert 处理的name为My object
第二个好理解,因为在调用前用that 保存了object 自己的this,所以that 就成为是有变量,在闭包内可以调用。
第一个有点晕,因为第一个的this指向自己,然后被window 给调用this 就成了window对象,它的name就是全局的name


引用陈守川的发言:

我觉得大家说了这么多,都没人把代码写出来运行一下来验证自己的答案么,也不管自己的答案是否正确么。通过运行发现:
思考题一:打印:空白
思考题二:打印:My Object
虽然我不太了解,但是评论中的很多人自己也理解错误了。

这篇文章流传很广,看了多次,忍不住要问了。下面这句话:
---------
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
-----------
请问有哪种语言是“不”可以在函数内部直接读取全局变量的? 全局变量什么意思,就是在任何地方都可以读取。

引用忍不住要问了的发言:

请问有哪种语言是“不”可以在函数内部直接读取全局变量的? 全局变量什么意思,就是在任何地方都可以读取。

我觉得这句话可以改成:
Javascript语言的特殊之处,就在于函数内部可以直接声明(不使用var)并读取全局变量。

引用忍不住要问了的发言:

这篇文章流传很广,看了多次,忍不住要问了。下面这句话:
---------
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
-----------
请问有哪种语言是“不”可以在函数内部直接读取全局变量的? 全局变量什么意思,就是在任何地方都可以读取。

同感啊,一直对此很费解

感觉基本是参考《javascript高级程序设计》这本书里面的

本文关闭,不再接受回复。

微博 | 推特 | GitHub

2018 © 我的邮件 |阮一峰的网络日志 » 首页 » 档案

分类:

 

学习Javascript闭包(Closure)

作者: 阮一峰

日期: 2009年8月30日

珠峰培训

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

  var n=999;

  function f1(){
    alert(n);
  }

  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

  function f1(){
    var n=999;
  }

  alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

  function f1(){
    n=999;
  }

  f1();

  alert(n); // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

  function f1(){

    var n=999;

    function f2(){
      alert(n); // 999
    }

  }

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

  function f1(){

    var n=999;

    function f2(){
      alert(n); 
    }

    return f2;

  }

  var result=f1();

  result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。

  function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());


代码片段二。

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()());

(完)

一灯学堂

QCon 北京2018

相关文章

留言(121条)

讲的很清楚明了,连我都懂了,要是我们大学时的老师也能这么讲课。。。他们只会放幻灯片

这里有个 PPT 用于说明 JS 闭包,说明得很透彻: http://www.gracecode.com/archives/2385/

呵呵,可以作为面试题了!

闭包个人感觉是一种描述函数内部的数据结构,来描述函数的运行上下文.Javascript编程精粹 这本书算是讲的比较好一点.

类是有行为的数据,闭包是有数据的行为。

阮兄:
有点疑问:
function f1(){

    n=999;

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999
可以写成如下的不也一样么?

function f1(){

    n=999;

    return n;

  }
var result=f1();
alert(result);

@tt 实际上后种方法每次调用 f1 时,都会声明 n = 999,而且 n 无法保留状态值(严格按照你的代码,其实 n 为全局变量,我理解你的本意为 var n = 999;)。

而第一种 f1 实际上返回的是个匿名函数,这样 n 作用域被另外个 f2 函数作用域所使用,因此它会保留。n 不会被重复声明,且内容会被保存

这是我见过最简单易懂的闭包教程。

支持下。

博主的博客写的不错,简单易懂,东西涉及的很多方面我都有兴趣,看来是同道中人,^_^

一文中的!!!!!!!!!!!!
学习了!!

想知道思考题的答案,
我以为是:My Object

顶楼主,我读了一些文章。不是特明白。
有个问题。
记得有人说。外面的函数是closure,
好像楼主说里面的函数是closure.

不知道到底哪个是?谢谢。

楼主讲讲最后一个思考题,没明白

请版主讲一讲最后一个例子怎么回事,没有看明白

函数中的this一般是指向window中的变量。

引用hou的发言:
请版主讲一讲最后一个例子怎么回事,没有看明白

上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。

如果非要指向object,可显式的控制--把代码的最后一句改为 alert(object.getName().call(object));

阮大哥讲的很透彻 受益匪浅

大道至简,给予我这个初学者很大的帮助,谢谢!

浅显易懂,很好。

如下看法,认为有待商榷:
#1、有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

#2、这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
//如果 #1 说法正确,下句会打印10,实际结果是test未定义。
//alert(test); // error test 未定义
  
//如果 #2 正确,语句 nAdd(); 位置在何处应该都能执行,测试结果在下面这个位置,也就是语句 var result=f1(); 前。是不能执行的。
//nAdd();
var result=f1();
result(); // 999
  nAdd();
result(); // 1000

To 过客:

函数内部定义的方法和变量,要等到函数执行过以后,才会真正定义

但是从过客说的里面可以引出另外的问题,当使用这样的代码时。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }

如果在函数f1定义之前添加变量定义

var n = 1;
然后调用
f1()();
则显示为999。说明nAdd中的n确实是作为全局变量存在。于是问题就来了——有什么方法让他可以是父函数中定义的n呢?

大道至简,很不错!~ 这篇文章我要转了...

引用George Wing的发言:

函数中的this一般是指向window中的变量。

this关键字代表的实例会根据环境不同而变化的. 他总是指向owner 看看这篇你大概就动this这个关键字了

http://www.quirksmode.org/js/this.html

最后一个题感觉和闭包没什么关系啊,能详细解释一下吗?因为当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象,这在《Javascript权威指南》上说的很清楚,所以答案肯定是“The Window”,和闭包没什么关系啊

最后一题重点在this

如果把f2申明成全局变量,道理一样吗?

太经典了!
终于理解了,一箭双雕啊!既理解了this的用法,又理解了闭包

这个例子很不错,真的是一箭双雕

前面讲得挺好的,浅显易懂。对最后的两个例子搞不清楚为啥。版主能不能具体分析下。
var obj=function()
{
var MyFunc=function()
{
alert("hello world");
}
return function()
{
return MyFunc;
}
}()
var f3=obj();
var f4=obj();
alert(f3 === f4);//为啥是TRUE;搞不懂

最后两个例子很精炼 ^ ^

尝试解答代码段一:
getNameFunc: function() {//假设函数名为A
return function()/*假设函数名为B*/ { return this.name; };
}
在函数里面构建函数的时候,闭包产生。
在函数B内调用函数A的this.name,由于函数A没有name属性,所以就去找全局变量name,找到了,所以返回“The Window”,要是没有找到,则返回“undefined”。

代码段二可以尝试将代码更改为:
var _this = this;
return function() { return _this.name +"__"+ this.name; };

只有一点没弄懂,如下代码,nAdd在函数外为什么可以有意义?而test不行?想了好久,不知道那里有解答
  function f1(){
test=10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }

通俗易懂,, 阅览无数教程, 看了这篇, 终于明白了点.

写得太好了

这篇文章是阮兄一贯的风格,我喜欢,不过 "Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。"这句有点奇怪,c不一样可以在函数内部直接读取全局变量么?难道不是么?

阮大哥能不能具体讲下最后的思考题啊? 感觉关键在this

变量的作用域无非就是两种:全局变量和局部变量。
这句话值得商榷, 变量的作用域确实只有两种, 不过他们是全局对象和函数.
你想说的或许是变量的类型有两种?

理解最后两个例子:

1 函数中的this指的是调用这个函数的owner
2 object.getNameFunc()是返回一个函数,并没有执行函数中的代码
3 增加一个例子0:

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
return (this.name);
      }
  };
var name = object.getNameFunc();
  alert(name); 

4 把例子1变成

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name; //这个this是有上下文的限制的
      };
    }
  };
var tmp = Object.getNameFunc(); //此时没有执行this.name
var name = tmp();//这个时候才执行,这时候的this上下文为全局
alert(name);
//alert(object.getNameFunc()())

5 把例子2变成:

var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
var tmp = Object.getNameFunc(); //这个时候执行了that = this,这里的this上下文是object,所以that指的是object
var name = Object.getNameFunc(); //这个时候执行了that.name
alert(name);
//alert(object.getNameFunc()()); 

引用Jason的发言:

但是从过客说的里面可以引出另外的问题,当使用这样的代码时。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }

如果在函数f1定义之前添加变量定义var n = 1;然后调用f1()();则显示为999。说明nAdd中的n确实是作为全局变量存在。于是问题就来了——有什么方法让他可以是父函数中定义的n呢?

var n = 1;
function f1(){
	var n = 999;
	nAdd = function(){
		n++;
	}
	function f2(){
		alert(n);
	}
	return f2;
}
var b = f1();
nAdd();//n = 999+1 = 1000
b();//弹出 n 的值是 1000 (闭包内的变量n)
alert(n);//弹出n的值是 1 (全局)
全局的函数 nAdd 和 由f1返回的函数中 所使用到的变量n全部为f1函数内的局部变量n,而不是全局变量n,证据就是上面的代码中最后一句 alert(n) 弹出的值是1, 也就是说 nAdd中的n++并没有改变全局变量中n的值.

你自己描述的是 f1()() 显示的是999,说明 n 是使用的f1内部的变量n,而非是全局变量n,不知道你为什么会有

说明nAdd中的n确实是作为全局变量存在。
这种想法呢? 如果想在nAdd中使用全局变量n(即在函数外面定义的n)的话,使用window.n来访问.

楼主文章中的:


二、如何从外部读取局部变量?

这一整大段中的
n=999;

根据整篇文章所表达的内容,应该为:
var n=999;

因为如果没有加var,则声明的是全局变量,既然是全局变量,则在所有函数内部都是可见的,也就不会存在闭包这种说法.

请求楼主修正.

引用小彘的发言:

前面讲得挺好的,浅显易懂。对最后的两个例子搞不清楚为啥。版主能不能具体分析下。
var obj=function()
{
var MyFunc=function()
{
alert("hello world");
}
return function()
{
return MyFunc;
}
}()
var f3=obj();
var f4=obj();
alert(f3 === f4);//为啥是TRUE;搞不懂

因为f3和f4都指向同一个地址(即MyFunc).


var obj = (function() {
var MyFunc=function() {
alert("hello world");
}
return function() {
return MyFunc;
}
})();
var f3=obj();
var f4=obj();
alert(f3 === f4);//为啥是TRUE;搞不懂

我测试了一下,为什么第一个例子输出的什么都没有是null,第二个我理解是myobject。谁能解释下

引用小秦的发言:

请求楼主修正.

谢谢指出,已更正。

起初以为函数内用var声明变量,就等于用了this声明,其实不是
var w=100;
function f1(){
//var w=101;
//this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:100

var w=100;
function f1(){
var w=101;
//this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:100

var w=100;
function f1(){
w=101;
//this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:101

var w=100;
function f1(){
//var w=101;
this.w=102;
function f2(){
document.write(this.w);
}
return f2;
}
f1()();
输出:102

看起来函数中的var和this并不是一个概念,函数内的局部变量与函数的属性不是一回事,不过通过上面的情况能够加深理解this和闭包

很不错的讲解,楼主写的通俗易懂,很棒的理解,很受用!我的qq:290913917 希望有机会成为共同研究javascript和html5的伙伴,谢谢!

我感觉第一个思考题是不是这样理解:
首先this指向的是当前运行该函数的对象,
1、object.getNameFunc()得到了一个函数,函数为function(){return this.name}
2、object.getNameFunc()(),此时为window运行该函数,所以this指向的是window,所以this.name为The window

做习题之前有一点需要很清楚:

内部函数可以访问定义它们的外部函数的参数和变量(除了this和arguments之外)
如果需要访问对象的name属性的话,就需要显示的定义一个变量that来引用this,而这个变量此时就指向object对象了。

第一题改成下面这样就很清楚了。getNameFunc的第一个()是属于方法调用,所以this绑定到了object对象,自然this.name为"My Object",但是闭包函数无法访问这个this,它只能访问到全局的this。

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
alert(this.name);
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());

写的真不错。。。看了很多文章讲闭包都是云里雾里的。。看了本文才恍然大悟。。。哦原来闭包如此简单。。。。楼主写的不错。。。

前面讲的我都明白,但是最后两个例子还是不明白,好多处都不懂!
1. var object = {。。。} 这是在干什么?是在声明一个变量?还是在声明一个类,然后里面有许多属性?

2 . object.getNameFunc()(); 怎么会有两个括号?


3. 如何判断 this指向的是object 对象还是全局对象 ?

闭包是运行时中的概念,不能讲哪个函数是一个闭包!而是哪个函数在运行时存在一个闭包!有时候,好几个函数都可以组成一个闭包呢:
function ff()
{
var local=1;
this.add1=function()
{
return ++local;
};
this.add2=function()
{
return ++local;
}
}

var f=new ff();

alert(f.add1());//2
alert(f.add2());//3

最后两个例子中,第一个其实不是闭包,第二个是,但第二个例子其实不用那么复杂,直接把第一个例子中的this去掉就可以了。

为什么第一个运行以后结果是result?!既不是window也不是object....???

 function f1(){
    n=999;
  }

  alert(n); // error

这段代码在IE8和FIREFOX5上根本不能运行,求解释...

@eva 
function f1(){
    n=999;
  }

  alert(n); // error
很明显啊,全局变量n是在函数f1中定义的,你不调用函数f1,n怎么定义呢
function f1(){
    n=999;
  }
f1();
  alert(n);
这样不就OK了

At this time enhancements in could also be noticed in a point of contention.

思考题中的例子貌似是 javascript高级程序设计里的。今天刚看到。

你真是个有趣的人,为什么我总能在你这里找到我感兴趣的博文?……

楼主可以解释一下思考题一吗?我看很多人跟我一样都不是很懂思考题一啊,万分感谢!

引用Legend1988的发言:

楼主可以解释一下思考题一吗?我看很多人跟我一样都不是很懂思考题一啊,万分感谢!

同问,为什么this在嵌套函数中的意义不一样

this始终表示调用者的应用,第一个的闭包返回出来的一个函数,就是在window的环境下调用了这个函数,所以这个this是指向的window,而第二个把this保存在了that中。不知道说清楚没有

不错,小伙子讲的很到位,比一些书上生硬的翻译要好一些。Good!

后面第1个例子怎么输出result, result 是什么意思

@陈锐达:

根据您的解释,运行结果是不对的!如在A中定义name,执行结果一样

实际上,我认为闭包只是给外部函数提供了一个操作局部变量的途径,局部变量本身并没有改变,仍然为局部变量。

我也觉得最后两个例子,好像跟this的关系更大……

@tt 发问需谨慎, 文中的写法是一种类的写法, 域里有动作,你这个是函数。

渐渐地对闭包和this有点了解,尤其加上各位网友的激情讨论,并附上示例,通俗易懂!

引用Joe的发言:
最后两个例子中,第一个其实不是闭包,第二个是,但第二个例子其实不用那么复杂,直接把第一个例子中的this去掉就可以了。

不行哦,一定要引用一次,不然还不是闭包。

引用apple的发言:

this始终表示调用者的应用,第一个的闭包返回出来的一个函数,就是在window的环境下调用了这个函数,所以这个this是指向的window,而第二个把this保存在了that中。不知道说清楚没有

我赞成。。

个人觉着楼主说的不是闭包

初学者就这么理解闭包,最好不过了。

思考题答案:The Window、My Object;其实最关键的就是要明白作用域链和闭包所起到的作用,其实闭包说到底就是一个函数,而且函数调用返回后其资源所占用的栈区并没有释放,,所以变量就还保存在内存中,由于作用域链的关系,它会去寻找离其最近的var声明,var声明所在就是该闭包所在的层,从而在这层里面所得到的结果就是它最后的值,于是乎返回值也就是这个最终的值了

最后两道思考题~ 其实和函数调用还有关系的~ 在以上例子中使用的是函数调用的方式,this这时候是指全局变量

引用afity的发言:

最后一题重点在this

正解,和闭包有什么关系啊

引用红雨的发言:

正解,和闭包有什么关系啊

对于代码片段一

object.getnameFunc() 返回的匿名闭包函数被全局变量所引用,其中的this指向

全局变量,当执行时打印The Window 。

对于代码片段二

object.getnameFunc() 在返回闭包函数前,将this赋给that,此时getnameFunc是由

object调用的,故而this指向object,当内部函数被返回时,由于闭包的特性,仍然

能访问到外部函数中的值,当执行打印My Object 。

代码段一、
当一个函数作为函数而不是方法调用的时候,这个this关键字引用全局对象。容易令人混淆的是,当一个嵌套的函数(作为函数)在一个包含的函数中调用,而这个包含的函数是作为方法调用的,这也是成立的:this关键字在包含的函数中有一个值,但是它却(不太直观地)引用嵌套的函数体的内部的全局对象。
所以第一个打印出来的是"The Window"
代码段二、
由于this关键字不是在包含的函数中引用的,而是通过that=this这个调用的,所以这个this不是在闭包内的,因此这个this就不能调用函数体内的全局对象,而是他的局部对象object.name,所以第二个打印出来的是"My Object"

说多无用,关键是理清函数什么时候作为对象使用,什么时候作为函数使用。

object.getnameFunc()() 也可以改为object.getnameFunc().call()
这就是javascript狡猾的地方。

讲得很易懂 ··· 然后,最后思考题 感觉 是this关键字的问题,暂时还不懂··

谢谢,关于闭包本身的概念非常清晰, 不过我当初读你这篇文章的时候最大的困惑是为什么要搞出闭包这个东西来, 我这里写了我的理解

http://www.hetaoblog.com/myblogs/post/javascript-closure-chain-scope-anonymous-function-module.jhtml

请问阮兄/各位高人,假如某个JavaScript的函数对象已被调用过一次,如何用代码验证/判断当该函数对象被第二次调用时,它是新创建的还是使用的内存中已有的?

引用tomwang的发言:
最后一个题感觉和闭包没什么关系啊,能详细解释一下吗?因为当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象,这在《Javascript权威指南》上说的很清楚,所以答案肯定是“The Window”,和闭包没什么关系啊

完全赞同这位仁兄的看法!!前面闭包讲的不错,但是最后面的思考题出的很烂啊,跟闭包没关系,让人看完了反而糊涂了!

有个特别大的疑问:

……原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,……

f2真的被赋给一个全局变量了?

引用hanvslin的发言:

完全赞同这位仁兄的看法!!前面闭包讲的不错,但是最后面的思考题出的很烂啊,跟闭包没关系,让人看完了反而糊涂了!

最初我也以为思考题与文章主题无关,这两天在反复看 JavaScript 权威指南 函数一章,都看晕了...
产生闭包效果的环境必须是嵌套函数的引用被保存到了一个全局作用域里面,也不难理解 阮老师思考题的设计了

在退出函数之前,将不使用的局部变量全部删除。

请教一下这个改如何做?不太明白。。。Thanks!

保留内存值的解释有点不好,即使var result = f1(); 即使这里不赋值给全局变量result,通过f1()();也不会改变n的值,呵呵~

后面的思考题 阮哥能解释一下吗 
前面的例子是看懂了 但是思考题还是不会做

引用SpiderMan的发言:

感觉这里的例子更好一些 https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Closures

这里对于闭包的讲解好一点:普通的函数内嵌,内部函数是先执行;而闭包则是:先把内部函数赋给外部函数,然后在执行。

跟阮老师学JS!

感觉应该从js作用域链及其原理来分析闭包,这样才能彻头彻尾明白!

引用George Wing的发言:

上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。

这里说的this才是正确的。如果将此处的this能够轻松的理解,我想本文的最后一道题就懂了。你怎样认为呢?

每个函数在被调用时,其活动对象都会自动取得两个特殊变量:this和arguments。内部函数在搜索这个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量(这一点通过前面的图可以看得更清楚)。意思就是说找到匿名函数中的this和arguments就不会再往下找了(这里的往下指的是外层的包含函数,和最外层的window全局环境),而匿名函数的this对象通常指向window,所以输出的是全局的那个字符串。不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了

不执行调用f1肯定不可能生成test变量,第二个问题同样的原因。


引用过客的发言:

浅显易懂,很好。

如下看法,认为有待商榷:
#1、有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

#2、这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

  function f1(){
test = 10;
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
//如果 #1 说法正确,下句会打印10,实际结果是test未定义。
//alert(test);// error test 未定义
  
//如果 #2 正确,语句 nAdd(); 位置在何处应该都能执行,测试结果在下面这个位置,也就是语句 var result=f1(); 前。是不能执行的。
//nAdd();
var result=f1();
result(); // 999
  nAdd();
result(); // 1000

引用George Wing的发言:

上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。

哦。看了你这个解释就了解了

说的很易懂,最后两个例子还是有点模糊

为什么话要反着说呢,应该说正例,这着用太糟糕了,赞同 @迷途小书童 @steven

引用tomwang的发言:

最后一个题感觉和闭包没什么关系啊,能详细解释一下吗?因为当一个函数作为函数而不是方法来调用的时候,this指向的是全局对象,这在《Javascript权威指南》上说的很清楚,所以答案肯定是“The Window”,和闭包没什么关系啊

《Javascript权威指南》上说:如果嵌套函数作为函数调用,其this值不是全局对象(非严格模式下)就是undefined(严格模式下); 如果嵌套函数作为方法调用,其this值指向调用它的对象。所以代码片段一,getNameFunc()作为object的方法,所以this值应该指向调用它的对象(object),而object自己定义name为"My Object",所以片段一,我觉得应该是弹出"My Object"。我是新手,我只是从this方向对这个函数分析,有错误的地方,还望高手指点。

“闭包的概念”这一节总结的非常好,浅显易懂。同时,也了解了闭包的两个用处:一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

最后两个例子关键是区分object.getnameFunc()调用时和调用后的this指向。
第一个问题,object.getnameFunc()()函数在执行时this属于全局域,因此结果是the window
第二个问题,通过使用that=this 保留了在调用object.getnameFunc()时的this状态值。因此在getnameFunc()的闭包中访问的变量是已经不是this的了,而是that的~

JS新手,学习了,思考题和讨论很强大。

思考题解答(个人见解):
1、因为闭包最后的返回值是一个函数,注意紧紧是一个函数而已 并没有执行,等到alert调用时才执行,而这时执行调用的方法,前面阮老师说了,函数内没有var声明的事全局变量,所以调用的getName是一个全局的变量,所以对应this找到的是全局的name.
2、因为this的对象引用在编译时就已经确定了,就是object,所以返回值在Object中开始查找,找到了Obeject中的name就不到全局变量中查找。

综合各种理解之后,我明白最后的“代码片段一”中的闭包函数中的this是window对象,也就是说..闭包函数的范围竟然是window。。。

这么理解还不如不理解,这样下来对新手是一种误导。所以说才建议大家尽量都去看英文网站。唉

其实看完这篇文章,对于闭包的概念就有了更深刻的理解
最后留的两道题目,很好的说明了这一点。
因为第一题中getNameFunc这个方法或者叫函数是属于全局作用域的,所以里面返回的this始终都是指向window的。而第二题中用that=this改变了当前函数指向的作用域,所以第二题中的this最终只想的是myobject。
不知道我的理解正确不正确。
如果说错,请勿见怪...

return function() {
return this.name;
}
这里的this代表调用方法时所在的的作用域:全局作用域window。

return function() {
return that.name;
}
object.getNameFunc()()此处实现了从外部调用局部变量的方法,that会顺着作用域链向上级作用域查找,所以获得是getnameFunc的定义的变量var that = this。

@小彘:

是引用类型。f3和f4的值是指针,只想obj()。所以全等是true。

后两个应该this的作用域问题,不是闭包的问题吧。 弄的我都糊涂了... 还好找了一篇通俗的问题在,终于弄懂了

执行过f1这个函数后,test如果是局部变量会被销毁,如果是全局变量则会保存在内存堆(heap)里,如果不执行f1函数,test和nadd都是不存在的

不,我补充一下,我应该是说错了,既然f2函数是闭包,那么f2函数会保持它的外部函数f1的作用域,即使定义test为f1函数的局部变量(var test = 10);那么也要先检查f2是否对test产生引用,如果引用数为0,则在f1()调用完后销毁,再运行f1()()(实际上是调用f2函数)也不会产生对test这个局部变量的引用,所以它就在栈中被销毁了。
如果理解的不对,请大侠们拍砖

最后的思考题如果能理解这句话“this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的”,我想就能它们的运行结果了

this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。喜欢这句话,但是闭包还是没有理解透彻。

我觉得大家说了这么多,都没人把代码写出来运行一下来验证自己的答案么,也不管自己的答案是否正确么。通过运行发现:
思考题一:打印:空白
思考题二:打印:My Object
虽然我不太了解,但是评论中的很多人自己也理解错误了。

R兄講的非常簡單易懂。

我觉得是这样的,
第一个里边的this指向的是那个闭包函数,
第二个例子里边的this指向的是object。

引用陈守川的发言:

我觉得大家说了这么多,都没人把代码写出来运行一下来验证自己的答案么,也不管自己的答案是否正确么。通过运行发现:
思考题一:打印:空白
思考题二:打印:My Object
虽然我不太了解,但是评论中的很多人自己也理解错误了。

第一个 打印结果为 The window
第二个 打印结果为 My Object

第一个 this为全局对象,所以alert处理的name为The window
第二个 that 为object对象,所以alert 处理的name为My object
第二个好理解,因为在调用前用that 保存了object 自己的this,所以that 就成为是有变量,在闭包内可以调用。
第一个有点晕,因为第一个的this指向自己,然后被window 给调用this 就成了window对象,它的name就是全局的name


引用陈守川的发言:

我觉得大家说了这么多,都没人把代码写出来运行一下来验证自己的答案么,也不管自己的答案是否正确么。通过运行发现:
思考题一:打印:空白
思考题二:打印:My Object
虽然我不太了解,但是评论中的很多人自己也理解错误了。

这篇文章流传很广,看了多次,忍不住要问了。下面这句话:
---------
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
-----------
请问有哪种语言是“不”可以在函数内部直接读取全局变量的? 全局变量什么意思,就是在任何地方都可以读取。

引用忍不住要问了的发言:

请问有哪种语言是“不”可以在函数内部直接读取全局变量的? 全局变量什么意思,就是在任何地方都可以读取。

我觉得这句话可以改成:
Javascript语言的特殊之处,就在于函数内部可以直接声明(不使用var)并读取全局变量。

引用忍不住要问了的发言:

这篇文章流传很广,看了多次,忍不住要问了。下面这句话:
---------
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
-----------
请问有哪种语言是“不”可以在函数内部直接读取全局变量的? 全局变量什么意思,就是在任何地方都可以读取。

同感啊,一直对此很费解

感觉基本是参考《javascript高级程序设计》这本书里面的

本文关闭,不再接受回复。

微博 | 推特 | GitHub

2018 © 我的邮件 |

【电子通识】TINA-TI怎么使用受控源向导创建受控源 TINA-TI怎么使用受控源向导创建受控源 阅读详情

相关推荐

激光定位算法竞技场:hdl_localization与Cartographer/AMCL的横向技术解剖

本文深入对比了hdl_localization、Cartographer和AMCL三种激光定位算法的技术原理与性能表现。通过UKF-NDT融合、图优化和粒子滤波等核心技术,分析了各算法在结构化环境、动态环境和大尺度场景下的适应性。实验数据表明,Cartographer在全局一致性上表现最优,而AMCL在动态环境中更具鲁棒性。文章还提供了算法选型指南和参数调优技巧,为工程实践提供参考。

weixin_29062865的博客 365

js闭包是什么?

一、闭包是什么?   闭包(closure)就是能够读取其他函数内部变量的函数。在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成 “定义在一个函数内部的函”。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。(闭包的最典型的应用是实现回调函数(callback) )。 二、JS中闭包的优缺点及特性   → 优点:     1.保护函数内的变量安全...

weixin_39194176的博客 1万+

芯片低功耗设计的两种常用EDA流程

如题。

EricWZY2008的专栏 5557

JS中的闭包

闭包

web$-小白 9207

利用SPSS实现逻辑回归,树模型,以及广义线性模型

本案例是IBM SPSS数据分析与挖掘实战案例精粹----第九章的学习记录 案例背景:分析出导致急救后迟发性颅脑损伤的主要影响因素,共有201项案例: 分析思路:先使用logistic回归模型进行影响因素筛选,然后利用分类树探索自变量中是否存在交互作用,最后利用广义线性模型过程拟合带交互项的Logistic回归模型 字段:性别,年龄,收缩压,舒张压,血小板,脑挫伤,中线位移,脑肿胀,入院意识,是否手术急救,其余急救措施,是否出现迟发性脑损伤; ...

hepan_defeng的博客 1万+

STM32HAL库 基于外部Flash+FatFs模拟U盘方式进行固件拷贝升级(详解)

STM32HAL库 基于外部Flash+FatFs模拟U盘方式进行固件拷贝升级

qq_36075612的博客 1万+

闭包函数的理解

function fn() { return function () { //s; console.log("hello") return function () { //s1 console.log("world") } } ...

anhumi4350的博客 863

汽车电子电气架构

控制器:从多独立 ECU → 域控制器(DCU) → 中央计算平台 + 区域控制器,硬件集成度持续提升,冗余减少;算力:从分散无集中算力 → 按域分配算力 → 全域算力集中,算力量级从 MIPS 跃升至 TOPS,支撑高阶智驾;网络:从低速 CAN/LIN 独占 → 以太网为主、总线为辅 → 高速以太网主干,数据传输速率提升千倍;软硬件:从软硬件深度绑定 → 初步解耦 → 完全解耦(SOA),实现 “硬件预埋、软件解锁”;线束。

LXY_LXY_的博客 1436

js中什么是闭包?

闭包是指有权访问另一个函数作用域中变量的函数,简单理解就是,一个作用域可以访问另外一个函数内部的局部变量。可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员。4、在函数执行之前为函数提供只有在函数执行或引用时才能知道的具体参数;闭包:函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包。优势:延长外部函数内部变量的作用域范围,该变量不会被释放。2、函数外或在其他函数中访问某一函数内部的参数;3、在函数执行之前为要执行的函数提供具体参数;3、内部函数必须使用到外部的变量。

AnnieY_的博客 483

关于无障碍适配的笔记

针对无障碍兼容性的笔记,针对wcg2.0/2.1

CoffeeAndIce的博客 4215

PLC编程入门基础知识

PLC即为可编程逻辑控制器,实质是一种专用于工业控制的计算机,其硬件结构基本上与微型计算机相同。

SANRENYIXING的博客 2万+

js 闭包是什么?

1. 什么是闭包? 闭包(closure): 可以访问其他函数内部定义的变量的函数。在js中,只有函数内部的子函数才能访问到局部变量,所以,闭包可以理解为"定义在一个函数内部的函数"。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 2. 变量作用域 理解闭包,首先必须理解变量作用域。JavaScript 有两种作用域:全局作用域和函数作用域。定义在最外层作用域的变量是全局变量,定义在函数内部的变量称为局部变量,由于 JavaScript 的特性,外层的函数无法访问内部函数的变量;而内部函数可以访

RayShyy的博客 2943

黑猫带你学UFS协议第17篇:UFS安全模式详解(Secure Mode)

本文详细介绍了UFS协议中的安全模式,包括Erase, Discard, Purge和Wipe Device操作。Erase用于永久删除数据并确保无法恢复;Discard不保证数据清除;Purge类似于Sanitize,清除内部未映射的物理块数据;Wipe Device则是格式化设备。这些操作涉及逻辑单元、擦除单位、相关寄存器配置等,确保数据安全。" 126036669,12409270,MySQL 8.0 开窗函数详解,"['数据库理论', 'SQL']

黑猫奥利奥的博客 2559

javascript深入理解js闭包

javascript深入理解js闭包 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

记事本 3746

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

java script 闭包_让你分分钟理解 JavaScript 闭包

闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是 ECMAScript 规范给的定义,如果没有实战经验,很难从定义去理解它。因此,本文不会对闭包的概念进行大篇幅描述,直接上干货,让你分分钟理解闭包!闭包,一睹为快在接触一个新技术的时候,我首先会做的一件事就是找它的 demo。对于我们来说,看代码比自然语言更能理解一个事物的本质。其实,闭包无处不在...

weixin_29094301的博客 155

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

javascript深入理解js闭包,js 闭包

一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种:全局变量和局部变量。 Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。 Js代码   var n=999;   function f1(){     alert(n);   }   f1(); // 999 另一方面,在函数外部自然无法读取函数内的...

菜刀舞的快一点,武林高手也是难以近身的。 146

js闭包的理解

百度百科对闭包的定义闭包就是能够读取其他函数内部变量的函数。在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

z1093541823的博客 1850

JavaScript/JS闭包理解

JavaScript/JS闭包理解 本想写一篇关于JS闭包理解的总结。发现了有博主已经总结、分析的很到位了。推荐给大家: 深入理解JS闭包

qq_38787108的博客 655

js 闭包传参_javascript深入理解js闭包

一、变量的作用域要理解闭包,首先必须理解Javascript特殊的变量作用域。变量的作用域无非就是两种:全局变量和局部变量。Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。var n=999;function f1(){alert(n);}f1(); // 999另一方面,在函数外部自然无法读取函数内的局部变量。function f1(){var n=999;}alert(...

weixin_28760959的博客 422
上一篇: 掌握es6
下一篇: es6 let和var的区别
快乐的小z
博客等级 码龄9年 21粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值