Rumah > Soal Jawab > teks badan
三叔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的值了)
三叔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下!