js 点击闭包_JS闭包 - All_just_for_fun - 博客园

一.JS闭包

1.定义:

闭包是一个闭合容器,我们可以认为闭包是一个对象{key:value}

2.闭包形成条件:

缺一不可:

函数嵌套

内部函数引用外部函数局部变量

外部函数调用

3.作用:

延长外部函数局部变量的声明周期

从外部访问函数内部的局部变量

4.闭包缺点:

占用内存

不及时清除会造成内部泄漏

5.闭包示例:

1 functionfun(){2 var num = 123;3

4 return functionfun2(){  //函数嵌套 ==》满足15 console.log(num); //调用外部函数的局部变量num ==》满足26 }7 }8

9 var f =fun();10

11 f();    //外部函数调用 ==》满足312

13 f = null; //清除防止内存泄漏

分析:

当在var f = fun();执行结束时应该销毁函数fun以及内部变量num,但是由于执行到f()时需要使用fun()的局部变量num,则虽然fun()被销毁了但是内部num一直保留,直到f = null才结束。

6.使用闭包的场景:

解决循环遍历加事件监听的问题

将内部函数返回出来

将函数作为实参传递给另一个函数调用

(1)解决循环事件监听问题:

1 var btns = document.getElementsByTagName('button');2 console.log(btns);//btns为伪数组:具有数组的一般特性,可以下标取值也有length属性,但没有数组的一般方法不能排序等等

3

4 console.log(Array.prototype.slice.call(btns)); //将伪数组转换为一般数组

5 for (var i = 0; i < btns.length; i++) {6 btns[i].onclick = function(){ //异步方法

7 console.log(i);8 }9

10 }

分析:由于页面加载循环执行完毕,当按钮点击触发才会调用异步方法此时i值错误。

1 var btns = document.getElementsByTagName('button');2 console.log(btns); //btns为伪数组:具有数组的一般特性,可以下标取值也有length属性,但没有数组的一般方法不能排序等等

3

4 console.log(Array.prototype.slice.call(btns)); //将伪数组转换为一般数组

5 for (var i = 0; i < btns.length; i++) {6 (function(i) {7 btns[i].onclick = function () { //异步方法

8 console.log(i);9 }10 })(i);11

12 }

分析:此时按钮点击后打印i寻找上层作用域i发现正确。

(2)将内部函数返回出来:

1 functionfun(){2 var num = 123;3

4 return functionfun2(){ //作为内部函数返回出来5 console.log(num);6 }7 }8

9 var f =fun();10

11 f();12

13 f = null;

(3)作为实参传递给另一个函数调用:

1

2

3 functionfun(msg,time){4 console.log("fun执行开始");5 alert("fun执行开始");6 setTimeout(function(){7 console.log(msg);8 },time);9 console.log("fun执行结束");10 }11

12 fun("xxx",2000);

a1b8e4a45592b44fbcc91bb95a685581.png

补:

[1].同步与异步

同步:

同步会阻塞后续代码运行

同步没有回调函数

异步:

异步不会阻塞代码运行

异步必须有回调函数

[2].使用闭包自定义JS模版

1 (function(window){2

3 var str = "abc";4 var num = 123;5

6 functiongetstr(){7 returnstr;8 }9

10 functiongetnum(){11 returnnum;12 }13

14 //将闭包挂载到window的我们自定义的属性myModule上

15 window.myModule ={16 getstr:getstr,17 getnum:getnum18 }19

20 })(window)21

22 console.log(myModule.getstr()); //abc

7.例子

例1:

1 var name = "The Window";2 var object ={3

4 name: "My Object",5

6 getNameFunc: function() {7

8 return function() {9

10 return this.name;11 };12 },13

14 bb: {15 name: "bb",16 getNameFunc: function() {17 return this.name;18

19 }20 }21 };22 console.log(object.getNameFunc()()); //The Window

23

24 console.log(window.object.bb.getNameFunc()); //bb

分析:

1. console.log(object.getNameFunc()()); 相当于打印 window.object.getNameFunc()() 由于先执行

object.getNameFunc() 返回一个匿名函数,再执行 window.xxx() 最后得到this是指向外层的 window.name

2.同理可得bb

例2:

1 var name2 = "The Window";2 var object2 ={3 name2: "My Object",4 getNameFunc: function() {5 var that = this; //缓存this6 return function() {7 return that.name2;

8 };9 }10 };11 console.log(window.object2.getNameFunc()()); //My Object

分析:由于形成了闭包导致that没有被释放所以得到My Object

例3:

1 functionfun(n, o) {2 console.log(o)3 return{4 fun: function(m) {5 returnfun(m, n)6 }7 }8 }9 var a = fun(0)//undefined

10 a.fun(1) //0

11 a.fun(2) //0

12 a.fun(3) //0

13

14 var b = fun(0).fun(1).fun(2).fun(3) //undefined,0,1,2

15

16 var c = fun(0).fun(1)//undefined,0

17 c.fun(2) //1

18 c.fun(3) //1

分析:

a第一次赋值为一个Object对象,然后指针一直不变;b的指针一直改变;c一开始改变一次之后不变

1 var a = fun(0); ==> n=0,o=undefined; a={fun:function(m){ return fun(m,0)}}2 a.fun(1); ==> function(1){return fun(1,0)} ==> fun(1,0) ==> n=1,o=0

3 a.fun(2); ==> function(2){return fun(2,0)} ==> fun(2,0) ==> n=2,o=0

4 a.fun(3); ==> function(3){return fun(3,0)} ==> fun(3,0) ==> n=3,o=0

5

6

7 var b = fun(0). ==> n=0,o=undefined; b={fun:function(m){ return fun(m,0)}}8 fun(1). ==> function(1){return fun(1,0)} ==> fun(1,0) ==> n=1,o=0 ==> b={fun:function(m){ return fun(m,1)}}9 fun(2). ==> function(2){return fun(2,1)} ==> fun(2,1) ==> n=2,o=1 ==> b={fun:function(m){ return fun(m,2)}}10 fun(3) ==> function(3){return fun(3,2)} ==> fun(3,2) ==> n=3,o=2 ==> b={fun:function(m){ return fun(m,3)}}11

12 var c = fun(0). ==> n=0,o=undefined; b={fun:function(m){ return fun(m,0)}}13 fun(1); ==> function(1){return fun(1,0)} ==> fun(1,0) ==> n=1,o=0 ==> b={fun:function(m){ return fun(m,1)}}14 c.fun(2) ==> function(2){return fun(2,1)} ==> fun(2,1) ==> n=2,o=1

15 c.fun(3) ==> function(3){return fun(3,1)} ==> fun(3,1) ==> n=3,o=1

例4:

1 functionFoo() {2 getName = function () { console.log(1); };3 return this;4 }5 Foo.getName = function () { console.log(2);};6 Foo.prototype.getName = function () { console.log(3);};7 var getName = function () { console.log(4);};8 function getName() { console.log(5);}9

10 //请写出以下输出结果:

11 Foo.getName(); //2

12 getName(); //4

13 Foo().getName(); //1

14 getName(); //1

15 new Foo.getName(); //2

16 new Foo().getName(); //3

17 new new Foo().getName(); //3

分析:

1 注:2 1.对于同名的变量和方法,JS引擎会先将同名函数声明覆盖了同名变量的声明,然后定义同名变量3 2.new必须与函数在一起,生成实例化对象4 3.new与最近的小括号匹配5

6 function Foo() {...} ==>全局Foo函数7 Foo.getName = ... ==>Foo函数对象静态方法getName8 Foo.prototype.getName = ... ==>Foo原型对象中有getName属性9 var getName ==>全局变量getName10 function getName(){...} ==>全局方法11

12 执行步骤:13

14 ==>1.声明全局Foo()15 ==>2.声明全局getName()覆盖了getName变量声明16 ==>3.定义Foo.getName = function () { console.log(2);}; (Foo函数对象静态方法getName)17 ==>4.定义Foo.prototype.getName = function () { console.log(3);}; (Foo原型对象中有getName属性)18 ==>5.定义全局getName变量 = function () { console.log(4);};19 ==>6.执行Foo.getName(); Foo函数对象的静态方法执行 ==> 2

20 ==>7.执行全局getName(); ==> 4

21 ==>8.执行Foo().getName(); Foo函数对象执行完 ==> getName = function () { console.log(1); }; 修改了全局getName()22 ==> 返回this指向window ==> 执行window.getName() ==> 1

23 ==>9.执行全局getName(); ==> 1

24 ==>10.执行new Foo.getName(); Foo函数对象的静态方法执行并生成getName类的对象 ==> 2

25 ==>11.执行new Foo().getName(); ==>先执行new Foo() 的到一个Foo类的对象26 ==>Foo类对象.getName() 获得隐式原型对象__proto__的getName方法和Foo.prototype.getName()相同27 ==> 3

28 ==>12.执行new new Foo().getName(); ==>先执行内部new Foo()生成实例对象xxx ==>在执行new xxx.getName()29 ==>Foo类对象.getName() 获得隐式原型对象__proto__的getName方法和Foo.prototype.getName()相同,30 同时生成Foo.prototype.getName的对象 ==> 3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值