专栏名称: 前端JavaScript
分享 | 学习 | 交流 | 原创 分享是学习的开始;学习不必要从头开始,是从现在开始;交流能沟通你我,提高你的学识;期待你的加入!!! web前端技术交流,JavaScript,HTML5,CSS3……
目录
相关文章推荐
51好读  ›  专栏  ›  前端JavaScript

[S3-E401]关于闭包的理解

前端JavaScript  · 公众号  · Javascript  · 2017-08-15 07:22

正文


闭包:一个(存于内存的)封装好的数据或方法。


先讲封装好的固定数据,举个例子:


function testOne() {

 return 1 ;

 }

 var NumOne = testOne();

 console.log(NumOne);//1

上面这个栗子就是我对闭包的一部分理解。

在说下面的话题之前,必须又得提到一个关于‘()’的理解。

我的理解上:


1 . ()的意思可以理解成 '执行';函数赋值的时候是不用带上()的,执行的时候才需要。


举个栗子:


(function test(){console.log('hello Wolrd'})();//hello world

这实际上就等同于:


function test(){console.log('hello Wolrd'};

test();//hello world


2 . ()中可以带入参数,参数可以用于作为闭包函数执行时候的某个常量,这个常量对于外部来说是个变量。这样说可能有点绕,那么说句广告词可能会好理解点:开局只有一把武器...那么这武器,也就是()中的参数,它在游戏开始之前是一个变量,你可以选择矛,锤...但是进入游戏之后,这把武器就不可以改了,当你执行操作的时候,选择了矛的操作矛的属性,选择了锤的只能操作锤的属性。


结合()的第二个特征,再说一个封装好的动态数据,代码如下:


var spear = {operation:'刺'};

var hammer = {operation:'挥'};

function con_opera(t) {

return (t.operation);

}

console.log(con_opera(spear)); //刺

console.log(con_opera(hammer)); //挥

3.()的参数可以为多个,包括this,window,event等。


结合()的第三个特征,再端盘关于封装好的方法的栗子:


function plusFn(a,b){

console.log(a+b);

}

plusFn(3,4);//7



关于我对闭包的用途的理解 。


1.面向对象。


如果说现在现在有很多个玩家进游戏选角色的时候要捏人,如果从过程上去处理,那无疑是不够灵活的。

如果从对象上处理呢?

①.便于复用:

捏头(头部属性);捏身子(身子属性);捏手(手部属性);捏腿(腿部属性);

这样的话,只要写四个方法,就可以拼接成一个捏人的方法。而且可以重复使用这套方法,构成结构的多样性。

②.便于代码维护:

如果想要在身上捏对翅膀的话,完全可以再多加一个捏翅膀(翅膀属性);


2.异步处理。

因为闭包使用的是参数,而不闭包使用的是变量,之前解释过,参数为函数内部的常量,这个值在调用闭包的时候已经设置好,不会随着外界变量的改变而改变。

还有个是个人的习惯问题,我更喜欢的是写好一个方法,然后到处使用,尤其是ajax的时候,得到参数的处理方法,success的时候 fun(返回值),error的时候 fun(默认值),而且由于js的单线程多进程,频繁切换进程但同一进程却是按照顺序执行,这样的话,将方法闭包放入一个进程里面可以既方便又有效地避免异步引发的bug。


3.方便回调

从前有座山,山上有座庙,瞄里有个老和尚,老和尚给小和尚讲故事:。。。

这就是无限循环就是个回调函数。


(function test(){

 console.log('从前有座山,山上有座庙,瞄里有个老和尚,老和尚给小和尚讲故事:');

 test();

 })();



闭包题的分析:

这里从网上找了俩道比较经典的面试题,因为我实在也不知道它们初始出处是哪里,原谅我没法写引用地址。

1.

   for(var i = 1; i <= 5; i++) {

   setTimeout( function () {

      console.log(i);

      }, 1000 );

    } //5 5 5 5 5


改写一下:


function test(t){

setTimeout( function () {

      console.log(t);

      }, 1000 );

}

 for(var i = 1; i <= 5; i++) {

   test(i);

   } //1,2,3,4,5

   

这个就是异步的问题,如果使用闭包,闭包被调用的时候,console.log()分配的参数则是1,2,3,4,5这五个常量。而不闭包,则是瞬间去给五个console.log()分配了变量i,而i在内存中是一个变量,在setTimeout设定的时间到达时,已经是5了,这也是为什么一下子输出5个5的原因。


2.

function fun(n,o) {

  console.log(o)

  return {

    fun:function(m){

      return fun(m,n);

    }

  };

}

var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);

var b = fun(0).fun(1).fun(2).fun(3);

var c = fun(0).fun(1);  c.fun(2);  c.fun(3);


说实话,第一次做这题的时候,感觉在坐升降机,又像在看无限放大的漩涡。

return的意思为返回值,返回值的意思就一个函数的处理结果:加水(糖){return ‘糖水’}


a = fun(0);//fun(0,o),此时o为undefined,

所以console.log 一个 undefined 

return {fun:function(m)}

a = {

fun:function(m){

    return fun(m,0);

    }

}

a.fun(1) = function(1){

  return fun(1,0);

};

fun(1,0) = {

    console.log(0);

  return {

         fun:function(m)

         }

};//所以会console.log一个0

a.fun(2)与a.fun(3)同a.fun(1);


关于b fun(0).fun(1) == a.fun(1)//到这层为止,请参照a.fun(1)的解释。所以会console.log undefined,0;

fun(0).fun(1).fun(2)//这层 

fun(0).fun(1) = {

console.log(0);    

return{

        fun:function(m){

            return fun(m,1);

          }

      }

}则fun(0).fun(1).fun(2) = fun(2,1); //运行到fun(0).fun(1).fun(2)这层

fun(2,1) = {

    console.log(1);

     return {

             fun:function(m)

                 {

                  return fun(m,2);

                 }

            }

  }//所以会console.log一个1

  则fun(0).fun(1).fun(2).fun(3) = fun(3,2);//同理于fun(2,1),所以会console.log一个2

  

  //那么c这边就好解决的多了。

  c = fun(0).fun(1) //类似于a.fun(1); 所以会console.log undefined,0;

  c.fun(2)与c.fun(3)//参考b 的fun(0).fun(1).fun(2) ,所以会console.log 1,1.

  

  //所以最后答案为 undefined,0,0,0;undefined,0,1,2;undefined,0,1,1

  


以上就是我个人对闭包的不太全面的理解,写下来主要是为自己以后做个纪念,如果能帮助一些人则更为开心,有理解不足的地方希望大家多多提意见。



转自:https://segmentfault.com/a/1190000010604209

作者 : lackdata 


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

如果文章不错,请转发的朋友圈!

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

 ==========阅读原文==========