重新理解闭包,扒出来一个伪闭包?

2018-10-13 admin

七、

问题又来了

  • 按照最先前的说法,函数内部的函数必须被函数外部的一个变量给绑定了,这个函数才不会被垃圾回收机制给释放掉。
  • 那这个闭包内部的函数到底被外部的那个变量给绑架了呢?
  • 答案应该是input按钮~ ??不过这都是小问题了~

六、

fuc~我们把代码丢进浏览器,调试模式看看

想真正理解闭包,最终的办法还是要使用单步调试模式。

  • 在闭包作用域内分别翻翻三个input.onclick. Scopes 下面分别有三个Closure 包含了三个不同值的i 值分别是 i=0 i=1 i=2
  • 把断点打密一些,多看几圈,三次for循环每次都会给input 赋值一个i ,这就意味着,第一次循环结束时 第一个一个input.onclick.Scopes.Closure有值了后面两个是没有的,第二次循环结束,第一个和第二个有了,最后一个 没有。三次循环结束,三个input都各自有了属于它们自己的独立闭包~
  • 我理解应该是分别创建了三个独立的闭包,分别赋值给三个input

结论和我之前的猜测类似:

这特么根本就不是闭包?就是一个简单的赋值操作?利用了自调用函数,进行了三次赋值操作,分别把三行赋值给了三个按钮事件? 这特么根本就是个闭包!就是一个简单的赋值操作!利用了自调用函数,进行了三次赋值操作,分别把三行赋值给了三个按钮事件!

for循环滴溜溜转了三圈以后

三个input分别有三个i,值分别为:

i=0 i=1 i=2

接下来的调用就顺理成章了,每次点击按钮,直接去对应的闭包作用域内拿走i展示给用户就可以了

五、

现在我们把段三中的代码拿出来理解一番

<input type='button' value='按钮1'>
<input type='button' value='按钮2'>
<input type='button' value='按钮3'>

window.onload = function () {
    var aBtn = document.getElementsByTagName('input');

    for(var i = 0; i < aBtn.length; i++) {
        (function (i) {
            aBtn[i].onclick = function () {
            	console.log(i);
        	}
        })(i)
    }
}

  • 被嵌套在for循环里面的是一个匿名的立即执行(自调用)函数。
  • 这个长得跟四段中的那个函数完全不一样啊

www.w3schools.com/js/js_funct…

var add = (function () {
    var counter = 0;
    return function () { counter +=1; return counter }
})()
add();
add();
add();

  • 这是一个立即执行(自调用)的匿名函数内部匿名函数被赋值给了一个外部变量add这样这个 立即执行(自调用)的匿名函数 就不会被释放(垃圾回收机制回收)掉了。

现在我们再来看看这段代码:

function aa() {
    var aBtn = document.getElementsByTagName('input');

    for(var i = 0; i < aBtn.length; i++) {
        console.log(i+"a");
        (function (i) {
            console.log(i+"bb");
            aBtn[i].onclick = function () {
            	console.log(i);
		console.log(i+"ccc");
        	}
            console.log(i+"dddd");
        })(i)
    }
    console.log(aBtn[0].onclick)
       // ƒ () {
       //          console.log(i);
       //          console.log(i + "ccc");
       //      }
    console.log(aBtn[1].prototype)
       // undefined
    console.log(aBtn[2].onclick.constructor)
       // ƒ Function() { [native code] }
}
aa()
0a
0bb
0dddd
1a
1bb
1dddd
2a
2bb
2dddd

  • 控制台没有打印 ccc
  • 最内层的匿名函数被赋值到了三个外部变量aBtn[0].onclick aBtn[1].onclick aBtn[2].onclick 上面,不点击函数执行按钮,这个函数是不会被执行的。
  • 这特么根本就不是闭包?就是一个简单的赋值操作?利用了自调用函数,进行了三次赋值操作,分别把三行赋值给了三个按钮事件?

fuc~我们把代码丢进浏览器,调试模式看看

四、

于是翻出来百度百科对闭包的解释重新复习一遍,又有新的收获

function a(){
	var i=0;
	function b(){
		$(++i);
	}
	return b;
}

var c = a();
c();   // 1
c();   // 2
c();   // 3
c();   // 4

  • 闭包和JavaScript的垃圾回收机制有关
  • 闭包和JavaScript的函数生命周期有关
  • 正常调用完一个函数以后,这个函数以及函数内部变量都会被JavaScript的垃圾回收机制正确回收
  • 我们观察到:函数a() return出去一个嵌套在本函数内部的函数b()
  • 在语句var c = a()中,我们执行函数a(),就将函数a()的return值 函数b() 赋值给了变量c
  • 变量c此时就指向了函数b(),一个在函数a()外部的变量c指向了函数a()的内部函数b()
  • 垃圾回收机制看到a()函数外部变量c正在指向a()函数的内部函数b() ,当垃圾回收机制看到这种情况的时候,就不会把函数a()当成垃圾给回收掉。
  • 也因此函数a()的内部变量var i = 0 也得以幸存。

遗留问题:函数代码是保存在堆中还是保存在栈中?

如果在栈中,那就有意思了,难道栈不是按照严格的后进先出玩的?

闭包_百度百科

三、

将二段中视频中的代码详细抄出来理解一番,到闭包的时候,却不能解释清楚。

<input type='button' value='按钮1'>
<input type='button' value='按钮2'>
<input type='button' value='按钮3'>

  • var i是一个全局变量,for循环结束以后将i的值存储在全局变量i当中i=3, 每次点击按钮console.log(i)都会调用全局变量中的i=3;
  • 下次点击按钮时,i又被初始化为i=0,for循环会根据aBtn.length 重新计算i变量的值。
  • 点击按钮每次都会输出3;
window.onload = function () {
    var aBtn = document.getElementsByTagName('input');

    for(var i = 0; i < aBtn.length; i++) {
        aBtn[i].onclick = function () {
            console.log(i);
        }
    }
}

window.onload = function () {
    var aBtn = document.getElementsByTagName('input');

    for(var i = 0; i < aBtn.length; i++) {
        (function (i) {
            aBtn[i].onclick = function () {
            	console.log(i);
        	}
        })(i)
    }
}

  • 用let解决,let是块级作用域变量,函数每次调用结束以后都会释放掉块作用域内的所有变量。下次点击按钮时,i又被初始化为i=0,for循环会根据aBtn.length 重新计算i变量的值。
window.onload = function () {
    var aBtn = document.getElementsByTagName('input');

    for(let i = 0; i < aBtn.length; i++) {
        aBtn[i].onclick = function () {
            console.log(i);
        }
    }
}

二、

今天看到这个视频又讲到了闭包的一个用法。

www.bilibili.com/video/av203…

一、

之前做过不少的闭包练习,熟悉了闭包的写法。

小洋粉:闭包(closure)——封装

原文链接:https://zhuanlan.zhihu.com/p/46180934

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

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

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

文章标题:重新理解闭包,扒出来一个伪闭包?

相关文章
JavaScript数组对象实现增加一个返回随机元素的方法
本文实例讲述了JavaScript数组对象实现增加一个返回随机元素的方法。分享给大家供大家参考。具体如下: 核心特性: 概率随机、顺序随机、随机冒泡 本方法 来自个人手写 JavaScript 的实践,只涉及 JavaScript 1.5(...
2017-03-27
JavaScript使用pop方法移除数组最后一个元素用法实例
本文实例讲述了JavaScript使用pop方法移除数组最后一个元素的用法。分享给大家供大家参考。具体如下: 下面的代码演示了JS数组的pop方法,可以用来移除数组的最后一个元素,实际上就是把数组当成堆栈使用 &lt;!DOCTYPE ht...
2017-03-22
js判断子窗体是否关闭的方法
本文实例讲述了js判断子窗体是否关闭的方法。分享给大家供大家参考。具体如下: function InsideMessageAdd() { &#x2F;&#x2F;window.open()得到子窗体 tip = OpenDialog(&...
2017-03-29
深入理解JavaScript的React框架的原理
如果你在两个月前问我对React的看法,我很可能这样说: 我的模板在哪里?javascript中的HTML在做些什么疯狂的事情?JSX开起来非常奇怪!快向它开火,消灭它吧! 那是因为我没有理解它. 我发誓,React 无疑是在正确的轨道...
2017-03-26
JavaScript获取一个范围内日期的方法
本文实例讲述了JavaScript获取一个范围内日期的方法。分享给大家供大家参考。具体分析如下: 指定开始和结束时间,范围该范围内的所有日期放入数组 Date.prototype.addDays = function(days) { v...
2017-03-22
js日期范围初始化得到前一个月日期的方法
本文实例讲述了js日期范围初始化得到前一个月日期的方法。分享给大家供大家参考。具体分析如下: 今天做时间范围的初始化设定,开始时间是当前时间的前一个月,终于找到完美的解决方案了。 Date.prototype.format = functi...
2017-03-23
关于js里的this关键字的理解
this关键字在c++,java中都提供了这个关键字,在刚开始学习时觉得有难度,但是只要理解了,用起来就方便多了,下面通过本篇文章给大家详解js里this关键字的理解。 关于this,是很多前端面试必考的题目,有时候在网上看到这些题目,自己...
2017-03-29
JS实现带缓冲效果打开、关闭、移动一个层的方法
本文实例讲述了JS带缓冲效果打开、关闭、移动一个层的方法。分享给大家供大家参考。具体实现方法如下: &lt;!DOCTYPE html PUBLIC &quot;-&#x2F;&#x2F;W3C&#x2F;&#x2F;DTD XHTML 1...
2017-03-23
JavaScript将一个数组插入到另一个数组的方法
本文实例讲述了JavaScript将一个数组插入到另一个数组的方法。分享给大家供大家参考。具体分析如下: 这段JS代码可以通过Array.prototype.push.apply方法将一个数组插入到另外一个数组,下面的代码将数组b插入到a ...
2017-03-21
深入理解JavaScript编程中的原型概念
JavaScript 的原型对象总是让人纠结。即使是经验丰富的JavaScript专家甚至其作者,经常对这一概念给出很有限的解释。我相信问题来自于我们对原型最早的认识。原型总是与new, constructor 以及令人困惑的prototy...
2017-03-25
回到顶部