看了一张图终于明白啥是闭包了

2018-05-17 admin

闭包

闭包定义:指拥有多个变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。 函数内部可以直接读取全局变量。 函数内部变量无法在函数外部访问。 函数内部声明要用var或者let声明,不然会变成全局变量 链式作用域:子对象会一级级向上寻找父对象的变量,父对象的变量子对象都是可见的,反之则不行。 在一个闭包环境内修改变量值,不会影响另一个闭包中的变量。 普通的函数内嵌,内部函数是先执行;而闭包则是:先把内部函数赋给外部函数,然后在执行。

下面这段代码就是一根典型的闭包

function f1(){
    var a = 10;
    function f2(){
        alert(a);
    }
    f2();    //①
}
f1();        //10  ②

f1f1()的区别不加括号是代码,加()是执行这段代码,加return是返回一个值,可以把返回的值赋值给变量,不加return默认返回undefined

所以处有三种写法:

第一种:处写f2();处调用需要这样写f1();。具体执行过程:f1体内调用f2函数,并执行。

第二种:处写return f2();处调用需这样写f1();。具体执行过程:同上;区别是多了个return,因为现在f2函数中没有返回值,所以f1在调用f2只是执行一下alert(a)f1的返回值是undefined

第三种:处写return f2;处调用需这样写f1()();。这里返回的是f2函数的代码,所以在调用f1时要加上2个括号,第一个括号是执行f1函数,第2个括号是执行f2函数,如果处省略return会报错。

return和函数调用时是否加括号的意思都明白,但是把它俩结合起来,就搞不清了。

正好今天学闭包时碰上了,顺便就把它搞清楚了。

到底什么是闭包

对于新人(当然了是说我了),看很多闭包的定义,代码,还是不知啥是闭包,云里雾里的,这里感谢方方老师的文章JS 中的闭包是什么?,看完后,虽然还是说不出啥是闭包,但现在已经知道啥是闭包了,果然用图说话最牛逼。(图在文章中,我就不放出来了)

闭包的应用

MDN 上这个例子也写的很好 调用Counter.value()时,返回的是Counter内部的变量privateCounterincrement内部没有返回值,这个方法只是执行了privateCounter + 1操作,没有返回值; 同理decrement是将privateCounter - 1,也没有返回值; 所以执行Counter.increment,会返回undefined,但是接着操作Counter.value()时就可以得到1,因为执行上一步Counter.incrementprivateCounter+1了。

今天在下面三段代码上花费了大量的时间,一直似懂非懂,心里不踏实。

代码一:

var name = 'window';
var obj = {
    name: 'object',
    getName: function() {
        return this.name;
    }
};
obj.getName(); //object
(obj.getName = obj.getName)(); //window 非严格模式下

代码二:

var name = 'window';
var obj = {
    name: 'object',
    getName: function() {
        return function(){
            return this.name;    
        }
    }
};
obj.getName()(); //window

代码三:

var name = 'window';
  var obj = {
    name : 'object',
    getName : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
obj.getName()();    //object

今天在看阮一峰的博客学习Javascript闭包(Closure),对代码二、代码三部分很是不解,看到一网友搬出犀牛书(还没看过,我买了红宝石书才看了一点点)里的话,实在不解什么是作为函数调用,什么是作为方法调用;

《Javascript权威指南》上说:如果嵌套函数作为函数调用,其this值不是全局对象(非严格模式下)就是undefined(严格模式下); 如果嵌套函数作为方法调用,其this值指向调用它的对象。

又有一位网友说

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

看到这里大概明白匿名函数的作用域是全局,继续翻看下面评论,大概意思是说“把this保存在obj作用域下的一个变量中,this就在当前函数的作用域下了”。直到看完也是,似懂非懂,反正就是感觉哪里不对劲,但也说不上了。

直到看到【JavaScript】【函数】闭包闭包!这篇文章的代码一部分,终于明白其中的逻辑了。

下面就来分析其中的逻辑,我分析的方法就是把不懂的地方一个个用console打印出来

代码二和代码一的区别是多了一层嵌套函数,this值就不一样了。 ps:我一开始以为在代码二中再嵌套一层函数,就会打印出object =_=|||

先来看代码一,明白之后,另外两段代码自然就懂了。

为什么obj.getName()打印出来的是object,因为这时getName方法是在obj的作用域下,所以this指向obj,返回值当然就是object了。

接着看(obj.getName = obj.getName)()删掉右边后,打印出的结果变成了object,这就纳闷了。 ps:第一眼看上去,这啥玩意,把自己赋值给自己?这不是多此一举,直接用不就行了!

console.log打印出obj.getName后,终于拨云见天,obj.getName = obj.getName这句话的意思就是把getName函数赋值给自己,这个时候就不是obj.getName,而是getName匿名函数了,匿名函数通常用的方法是()()立即执行,此时再看匿名函数已经脱离obj了,当然this也就指向了全局,打印出window

代码三也就很好理解了。

闭包中引用循环变量

廖雪峰的闭包在文中就很形象的讲解了函数中的引用会变化的变量会有什么后果,我节选了他的结论和代码。

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。 如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i));
    }
    return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

f1(); // 1
f2(); // 4
f3(); // 9

这里的核心就是立即执行,如果不是立即执行的话,变量i就是for循环结束后的值了。

原文链接:https://segmentfault.com/a/1190000014894036

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-32388.html

文章标题:看了一张图终于明白啥是闭包了

相关文章
从 Node.js 分裂出 Io.js 事件看开源软件谁做主
Node.js 作为服务器编程语言的后起之秀,常用来构建和运行 Web 应用,近日却爆出其社区出现分裂。由于对官方运营商 Joyent 公司在 Node.js 管理上的长期不满,多位核心开发者另立门户,创建了分支 Io.js。从 GitHu...
2015-11-12
纯JS实现旋转图片3D展示效果
CSS: &lt;style type=&quot;text&#x2F;css&quot;&gt; #show{position:relative;margin:20px auto;width:800px;} .item{position:...
2017-03-22
前端问答社区成立了
由雷锋网友提供的给大家相互交流的前端问答社区正式上线了,欢迎大家来此相互交流相互学习 ...
2016-03-30
Html5 是否适合移动应用开发
HTML5最近这几年声誉鹊起,而基于HTML5技术的产品也风生水起。感觉现在你的产品要是不和HTML5沾点边,都不好意思和客户打招呼!移动应用开发中,HTML5更是不可或缺的角色,市面上不少移动应用中间件产品都号称支持HTML5,例如APP...
2015-11-12
HTML5会是下一个风口吗?
2014年10月底, W3C(万维网联盟)正式宣布HTML5正式定稿,科技圈就像发现了可以打破谷歌、苹果所统领的原生APP世界的方法,发表了很多宣讲HTML5将真正开始颠覆原生(Native)App的文章,也开始着力发展HTML5,开始抢占...
2015-11-12
JavaScript初学者必看“箭头函数”
本文我们介绍箭头 (arrow) 函数的优点。 更简洁的语法 我们先来按常规语法定义函数: function funcName(params) { return params + 2; } funcName(2); &#x2F;&#...
2017-05-26
何为闭包?有关JS闭包的一些理解
简单一点的说:闭包就是能够读取其他函数内部变量的函数。那如何实现读取其它函数内部变量呢,大家都知道在JavaScript中内部函数可以访问其父函数中的变量,那如果将内部函数返回是不是代表能够通过它访问其父函数中的变量了呢,闭包的原理事实上就...
2015-11-11
javaScript+turn.js实现图书翻页效果实例代码
为了实现图书翻页的效果我们在网上可以看到很多教程 在这里推荐turn.js 网上的turn.js 有api 不过是英文的  很多人看起来不方便 .关于代码也是奇形怪状在这里我将详细讲解如何使用turn.js实现翻页效果 ,本篇文章只是讲解 ...
2017-03-16
图片优化的那些工具
图片作为页面的一个主要因素,它的大小直接影响了页面的加载速度,这一点在移动端尤显突出。 怎么让图片的大小更小?除了选择合适的格式(jpeg、gif、png),我们还可以利用网上的应用(如smushit、tinypng、imagemin、im...
2016-01-13
百度新功能【特效搜索】演示 惊呆了小伙伴
百度搜索最近又出新玩意新功能了,可能你还没有发现,名为【百度特效搜索】已经默默上线了,有什么效果呢? 在百度搜索中根据用户搜索的关键词来出发某些动作,例如笔者搜索“打雷”关键字,在搜索结果中你会听到有打雷声, 黑洞,闪烁、翻转、跳跃,打雷,...
2015-11-12
回到顶部