摘要:注意由定义可以知道,闭包函数肯定是定义在函数中,才可能有上级的函数作用域可以访问,否则上级作用域就是全局作用域。造成这种结果的原因就是绑定的多个函数是闭包函数,他们共同使用保留的上级函数作用域中的变量。
1 闭包的定义
维持了自由变量不被释放的函数, 称为闭包,(自由变量指不在自身上下文,也不在全局上下文中的变量)。
那么闭包函数的特点在哪里,我们知道函数在创建的时候,它的[[scope]]属性就已经确定并不可以改变,所以闭包函数在创建的时候就保存了上级的作用域链,闭包函数通过作用域链去寻找使用到的变量,正常情况下,函数在执行完毕后,将销毁函数的执行上下文,但是由于闭包函数的存在,包含闭包函数的上级函数执行完毕后,如果闭包函数还存在,那么这个上级函数的作用域中的变量仍然保留在内存中供闭包函数访问。
注意:
由定义可以知道,闭包函数肯定是定义在函数中,才可能有上级的函数作用域可以访问,否则上级作用域就是全局作用域。全局作用域中的变量本身就一直在内存中,所以访问全局作用域中变量的函数不能称为闭包。
var name = "global"; function func1() { var name1 = "func1"; console.log(name); console.log(name); function func2() { console.log(name); var name2 = "func2"; function func3() { console.log(name2); } func3(); } func2(); } func1();
上面代码中,func3为闭包函数,因为它访问了上级函数作用域中的变量name2,func2不能称为闭包函数,因为它们访问的是全局作用域中的变量name。
2 常见的闭包场景 2.1 维持变量的闭包var person = (function(){ var _name = "yangyiliang"; var _age = 18; return { getName: function () { return _name; }, getAge: function () { return _age; }, addAge: function (num) { return _age += num; }, reduceAge: function (num) { return _age -= num; } } })(); console.log(person.addAge(5)); // 23 console.log(person.reduceAge(3)); //20
上面的代码中,首先外层包裹了一个匿名立即执行函数,创造了一个上级函数作用域,getName和getAge方法都是在其内部,并且访问了上级函数作用域中的变量,所以是闭包,所当匿名函数执行完毕后,本该销毁的执行上下文,却因为闭包函数而保留了作用域中的_name和 _age变量, 通过addAge 和reduceAge的结果发现,两个闭包共用保留的作用域。
2.2 维持参数的闭包function makeSizer(size) { return function() { document.body.style.fontSize = size + "px"; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16); document.getElementById("size-12").onclick = size12; document.getElementById("size-14").onclick = size14; document.getElementById("size-16").onclick = size16;
上面的代码中,makerSizer函数的返回值即为闭包函数,闭包函数访问上级函数作用域中的参数。
2.3 循环创建闭包常见错误
function bind() { var arr = document.getElementsByTagName("p"); for(var i = 0; i < arr.length;i++){ arr[i].onclick = function(){ alert(i); } } } bind();
上面的代码中,假设arr的length为5,想要实现的功能是点击5个P标签分别alert 0,1,2,3,4。但是事实上得到的结果却是都alert 5。
造成这种结果的原因就是绑定的多个onclick函数是闭包函数,他们共同使用保留的上级函数作用域中的变量 i 。 for循环执行结束后 i 的值即为5。
要想解决这种错误,就让这些闭包保存不同的上级作用域即可。
function bind() { var arr = document.getElementsByTagName("p"); for(var i = 0; i < arr.length;i++){ (function (i) { arr[i].onclick = function(){ alert(i); } })(i); } } bind(); 或者 function bind() { var arr = document.getElementsByTagName("p"); for(var i = 0; i < arr.length;i++){ arr[i].onclick = (function(i){ return function () { alert(i); } })(i); } } bind();
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/88064.html
摘要:但是我们知道中是没有重载的为什么没重载不是的特性也会有的吗,因为后面定义的函数会覆盖前面的同名函数,但是重载那么好用,我们想在实现函数重载该怎么办呢今天就来给大家讲讲在里面实现函数重载的两个思路。这就是闭包的核心作用。 大家都知道,所谓重载,就是一组相同的函数名,有不同个数的参数,在使用时调用一个函数名,传入不同参数,根据你的参数个数,来决定使用不同的函数!重载这个在JAVA这些经典的...
摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....
摘要:使用闭包遇到的陷阱一陷阱在类的原型对象中添加特权方法首先定义一个类,该类中有一个私有变量定义个特权方法来访问修改私有变量然后我们对类进行测试到目前为止,类正常工作。 使用JavaScript闭包遇到的陷阱(一) 陷阱:在类的原型对象中添加特权方法 首先定义一个Page类,该类中有一个私有变量dom: function Page(){ var dom; } 定义2个特权方法来访问...
摘要:什么时候需要用到单例模式呢其实单例模式在日常开发中的使用非常的广泛,例如各种浮窗像登录浮窗等,无论我们点击多少次,都是同一个浮窗,浮窗从始至终只创建了一次。这种场景就十分适合运用单例模式。 单例模式 什么是单例模式? 单例模式的定义:一个类仅有一个实例,并且可以在全局访问。什么时候需要用到单例模式呢?其实单例模式在日常开发中的使用非常的广泛,例如各种浮窗、像登录浮窗等,无论我们点击多少...
阅读 964·2021-11-22 13:53
阅读 1515·2021-11-17 09:33
阅读 2295·2021-10-14 09:43
阅读 2732·2021-09-01 11:41
阅读 2228·2021-09-01 10:44
阅读 2863·2021-08-31 09:39
阅读 1418·2019-08-30 15:44
阅读 1829·2019-08-30 13:02