recherche

Maison  >  Questions et réponses  >  le corps du texte

这个js函数的输出的结果不一样的原因是什么呢?

如图为什么结果会不一样呢

QQ图片20161125114704.png

高洛峰高洛峰2955 Il y a quelques jours1104

répondre à tous(4)je répondrai

  • 三叔

    三叔2016-11-25 14:37:25

    我是这样想的:function f1(){

                var n=999;
                nadd=function (){
                    n+=1;
                    console.log("n的值为"+n);
                }
                function f2(){
                    console.log(n);
                }
                return f2;
            }

    // f1();//这里还是指向的原对象
    // f1()();//undefined
    // nadd();//这里还是指向的原对象下面的方法--虽然是个闭包,但是因为是原对象的方法,且只调用一次,所以,正常输出1000;

    var r=f1();//这里还是指向的原对象的链接(可以认为r把原对象拷贝了一份),即此对象!==f1()

    // r();//这里是r(),即原对象的完成了拷贝,并且调用了f2方法,输出999,。如果是f1(),则不作输出(f1()下的方法都没被调用)

            nadd();//无论上一行是f1()还是r(),作为函数内的闭包,被调用一次(注意,当前它其实是r的路径指向的原函数下了)
            r();//如果前面为f1(),即意味着这里是var r=f1()拷贝后的第一次调用f2()输出999,如果前面为r(),即意味着这里是第二次调用,同样输出f2(),但是不同的是,前面的nadd()已经影响到了r中的n,即f1()中的var n=999;已经被替换为n+=1;并且已经执行一次了,所以,当前的n为1000(闭包保存了n)。

    这里可以再这样子试试:

            var r=f1();
            f1();//不作输出,r()没调用
            
            nadd();//n被保护,且加一,为1000;
            nadd();//n被保护,且加一,为1001;
            r();//999,因为这里才是r拷贝的路径后执行的第一次,在它复制的那一刻,n=999.所以f2()输出999

    内容有点多,不知道题主能明白我的意思不?说到底,其实主要是var r=f1()这一句造成的影响,它将f1()发状态冻结了,从而引发后面nadd()的结果(准确的说是让nadd()能够修改到n的值了)

    répondre
    0
  • 三叔

    三叔2016-11-25 14:36:19

    f1()()的时候f1()会重新执行var n = 999;而r()时,n = 999只在 r = f1()时执行了一次。

    répondre
    0
  • 三叔

    三叔2016-11-25 14:36:07

    因为每次函数调用都是不同的上下文,第二种方法f1只调用了一次,第二次调用r的时候,n还是之前的n,第一种就不同啦。

    répondre
    0
  • 三叔

    三叔2016-11-25 14:35:55

    每次进入一个函数,都会将里面的语句全部执行一次,第一次调用f1()()会定义一个函数级别变量n,并且将隐性全局变量的值设为一个函数,注意这个函数因为是在f1中定义的,所以它可以引用它创建时的所有变量,这也就是闭包的由来,对于没有闭包的情况,函数内的函数级别变量(函数内用var声明的)都会在函数结束后销毁,但是一旦存在闭包,也就是逃逸出这个函数级作用域的函数(不管你是通过返回函数,或者设置为全局变量),这个逃逸的函数,都可以访问它创建时的所有可见变量,阻止浏览器回收这些变量。
    每次调用f1是都会定义一个函数体完全一样但是却是不同函数的函数对象,所以第一次调用f1()后,已经形成了闭包:返回的f2盒全局的nadd,调用f1()()的结果就是调用了返回的f2,这时第一次调用f1时创建的n1(这个1代表它是第一次创建的,仅仅为了表述清楚,实际上它是n),就是999,然后调用nadd()n1被加一,所以输出了1000,但是你再次调用f1(),这时有趣的事情发生了,f1的函数体要再执行一次,看似好像nadd没有改变,但是其实它已经指向了一个新的函数,尽管这个函数的函数体和它之前的函数体是完全一样的,但是它们是不同的对象,最大的不同就在于可以访问的变量不同,第二次的nadd,可以访问的已经不再是n1,而是第二次调用f1()创建的n2了,这个n2的值为999,至于n1呢?它因为已经没有函数可以访问,被回收啦!因为返回的f2并未被存为变量而且第一次f1中定义的nadd也已经不在了。
    后面的为什么是那个结果题主可以自己想一下,闭包是js中的一个双刃剑,威力无穷也很蛋疼,但是只要好好思考是很好理解的,一旦理解,合理的使用闭包会带来很多好处,但是也有很多坑需要注意,具体的题主可以google下!

    répondre
    0
  • Annulerrépondre