1.什么是閉包形庭?
? ??????????閉包是指有權(quán)訪問另一個函數(shù)作用域的變量的函數(shù)。
????????????說白了厌漂,閉包就是一個函數(shù)萨醒,這個函數(shù)能夠訪問其他函數(shù)的作用域中的私有變量。每當創(chuàng)建一個函數(shù)苇倡,閉包就會在函數(shù)創(chuàng)建的同時被創(chuàng)建出來富纸。
2.我們都知道函數(shù)內(nèi)部可以訪問全局變量的,但還是內(nèi)部的變量外部訪問不到
????????function?fun?(){
????????????str='沒有用var'
????????????var?num=1
????????}
????????fun()//得調(diào)fun函數(shù)旨椒,如果不調(diào)str訪問不到晓褪,相當于全局只有fun
????????console.log(str,'str')//沒有用var?str-----(注:如果不用var聲明變量的話,實際上聲明了一個全局變量)
????????console.log(num,'num')//num?is?not?defined
3.外部如何才能拿到局部變量
????????function?fun1?(){
????????????var?str1='fun1--str'
????????????function?fun2(){
????????????????var?str2='fun2-str'
????????????????console.log(str1)//str1---可以拿到父級作用域的變量
????????????}
????????????console.log(str2)//不可以訪問fun2子函數(shù)中的str2變量
????????}
????????????在上面的代碼中综慎,fun1里面的變量fun2可以拿到涣仿,但fun2里面的變量fun1不可以拿到。這就是鏈式的作用域寥粹。子對象可以一層一層的向上找父級中的變量变过,父級里面的所有變量子都可以拿到埃元,但父級拿不到子函數(shù)作用域中的變量。
????????????1>如果我們想要獲取fun1中的變量怎么獲取呢媚狰?把fun2作為返回值
? ??????????????function?fun1(){
????????????????????var?str1='str1變量'
????????????????????return?function?fun2(){
? ? ? ? ? ? ? ? ? ? ????console.log(str1,'fun2中打印父級中的變量str1')
????????????????????}
????????????????}
? ? ? ? ? ? ? ?fun1()()//這里的fun1()調(diào)用返回的是fun2岛杀,fun1()()調(diào)用fun()的返回值fun2
????????????????上面的例子中返回的fun2就是閉包
? ? ? ? ? ? ? ? 注意:不管return不return? ? fun2都是閉包,表示一種狀態(tài)崭孤,子函數(shù)可以訪問父函數(shù)的變量类嗤,形成的語法環(huán)境組合
4.這些變量的值始終保存在內(nèi)存中
????????????????????function?fun1(){
?????????????????????????var?num=1
?????????????????????????return?function?fun2(){
?????????????????????????????num++
?????????????????????????????console.log(num,'num')
?????????????????????????}
?????????????????????}
?????????????????????let?result=fun1()
?????????????????????result()//2?"num"
?????????????????????result()//3?"num"
?????????????????????fun1()()//2?"num",因為---每調(diào)一次fun1開辟一個新環(huán)境
? ? ? ? ? ? ? ? ????上面之所以num編程6是因為,num并沒有因fun1的調(diào)用被回收辨宠,而是一直在內(nèi)存中
? ? ? ? ? ? ? ? ? ? ?因為fun1是fun2的父函數(shù)遗锣,而fun2被賦給了一個全局變量,這導致fun2始終在內(nèi)存中嗤形,而fun2的存在依賴于fun1精偿,因此fun1也始終在內(nèi)存中,不會在調(diào)用結(jié)束后赋兵,被垃圾回收機制(garbage collection)回收笔咽。
5.缺點
?由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大霹期,所以不能濫用閉包叶组,否則會造成網(wǎng)頁的性能問題,在IE中可能導致內(nèi)存泄露历造。解決方法是甩十,在退出函數(shù)之前,將不使用的局部變量全部刪除吭产。
請大家慎用侣监。
6.this問題解決的兩種方式
? ? ? ? 以構(gòu)造函數(shù)為例
? ? ? ? 1>手動賦值this
????????function?Fun(){
????????????this.str='222'
????????????this.fun2?=?function(){
????????????????let?self?=?this
????????????????return?function(){
? ? ? ? ? ? ? ? ? ? //這個閉包函數(shù)this指向是window
????????????????????console.log(self.str,'this.str')
????????????????}
????????????}
????????}
????????let?f1 =new?Fun()
? ? ? ? 2>ES6箭頭函數(shù)
? ??????????function?Fun(){
????????????????this.str='222'
????????????????let?str1=1
????????????????this.fun2?=?function(){
????????????????????return?()=>{
????????????????????????console.log(this.str,'this.str')
????????????????????}
????????????????}
???????????}
????????????let?f1 =new?Fun()
? ? ? ? ? ?再舉一個例子:
? ? ? ? ? ? ?這個例子,跟上面構(gòu)造函數(shù)的例子差不多垮刹。
? ? ? ? ? ? ?至于圖中為什么用let訪問不到全局變量中的str达吞。那是因為用 let 和 const 聲明的全局變量并沒有在全局對象(window)中,只是一個塊級作用域(Script)中荒典。