摘要:在不知道閉包之前,因為鏈?zhǔn)阶饔糜虻年P(guān)系只能向上一級的作用域查找變量,我一直認(rèn)為函數(shù)內(nèi)的變量在函數(shù)之外是無法訪問到的。其實閉包的理解很簡單,閉包就是能夠取得函數(shù)內(nèi)部變量的函數(shù)。在本質(zhì)上閉包其實就是鏈接函數(shù)內(nèi)部與函數(shù)外部的橋梁。
在不知道閉包之前,因為鏈?zhǔn)阶饔糜虻年P(guān)系(只能向上一級的作用域查找變量),我一直認(rèn)為函數(shù)內(nèi)的變量在函數(shù)之外是無法訪問到的。直到認(rèn)識了你--閉包,讓我徹底顛覆了之前的想法,也讓我明白了不要隨便下結(jié)論,要不你會死的很慘……
談到閉包或許會讓你想到匿名函數(shù),因為這兩個神奇的小怪物會常常讓人混淆。閉包呢是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù),我們創(chuàng)建閉包最常用的方法就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù),以下面為例就是一個最簡單的閉包:
function f(){ var num=10; function f1(){ return num; } return f1; } var result=f(); console.log(result()); //10
1、作用域
談?wù)撻]包之前呢還是需要想回顧一下變量的作用域問題。
作用域無非就是全局變量和局部變量。
這樣有引出了作用域鏈,在作用域鏈只能向上一級查找變量,所以說在函數(shù)內(nèi)部我們可以直接讀取全局變量,但在函數(shù)外部是無法讀取函數(shù)內(nèi)部的局部變量的。
我們都知道函數(shù)的執(zhí)行依賴于變量作用域,這個作用域是在函數(shù)定義時候決定的,而不是在函數(shù)調(diào)用時決定的??聪旅胬樱?/p>
var scope="global scope"; function checkscope(){ var scope="local scope"; function f(){ return scope; } return f; } checkscope()(); //local scope
嵌套的函數(shù)f()是定義在函數(shù)內(nèi)部的,其中的變量scope是局部變量,不管在何時何地執(zhí)行f(),作用域鏈?zhǔn)遣粫淖兊摹?/p>
var num1=10; function f1(){ var num2=20; num3=30; alert(num1); } f1(); //10 alert(num1); //10 alert(num2); //num2 is not defined alert(num3); //30
這里有一個需要注意的地方,函數(shù)內(nèi)部聲明變量一定要使用var,如果一不小心忘記了,那對不起了,你將聲明一個全局變量!
2、如何在函數(shù)外部讀取到函數(shù)內(nèi)部的變量呢?
但是在某種情況下因為一些原因我們是需要得到函數(shù)內(nèi)部的局部變量,但是前面我們也嘗試過了,在函數(shù)外部是無法得到內(nèi)部的變量的,怎么辦,這可愁死寶寶了……別急,辦法還是有的:
function f(){ var num=10; function f1(){ return num++; } return f1; } var count=f(); count(); //10 count(); //11 count(); //12 count(); //13 count(); //15
正如剛開始我們的例子,f1被包含在了f內(nèi)部,此時f的變量對于f1都是所謂的上一級,也就是都是可見的,隨時都可以訪問。既然f1可以讀取f中的局部變量,那我們只需把f1作為返回值即可在f外部取得f的局部變量了。
3、到底什么是閉包?
其實上一段代碼中的f1函數(shù)就是我們說的閉包。其實閉包的理解很簡單,閉包就是能夠取得函數(shù)內(nèi)部變量的函數(shù)。
在本質(zhì)上閉包其實就是鏈接函數(shù)內(nèi)部與函數(shù)外部的橋梁。
4、閉包的用途
說了好多,但是閉包到底有什么用,為什么要學(xué)習(xí)這個“違法”的怪物?閉包的用處實在是太多了,最最重要的就是:可以在函數(shù)外部讀取函數(shù)的變量,另一個就是讓這些變量的值永遠(yuǎn)保存在內(nèi)存中。what?莫急,請看下面代碼:
function f(){ var num1=99; add=function(){ num1+=1; } function f1(){ return num1; } return f1; } var result=f(); alert(result()); //99 add(); alert(result()); //100
為什么num1沒有在result()調(diào)用之后被清楚呢?原因就是f是f1的父函數(shù),f1最后是被賦值給了全局變量result,這導(dǎo)致了f1會一直在內(nèi)存當(dāng)中,然而f1的存在是依賴于f的,因此f也將一直在內(nèi)存中。
此處有玄機哦,注意add函數(shù)前面沒有var關(guān)鍵字,也就是說add現(xiàn)在是一個全局變量,而add的值是一個匿名函數(shù)(另一個小怪物),而這個匿名函數(shù)本身也是一個閉包(因為他訪問了局部變量num1),他可以在函數(shù)外部對函數(shù)內(nèi)部的變量進行操作。
5、閉包里的this
我們都知道,this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的:全局作用域下,this就是window,而當(dāng)函數(shù)作為某個對象的方法調(diào)用時,this等于那個對象(其實在全局作用于下,函數(shù)就是window的方法)。不過匿名函數(shù)的執(zhí)行環(huán)境是具有全局性的,因此this通常指向window。
var name="the window"; var object={ name:"my object", getNameFunc(){ return function(){ return this.name; } } } alert(object.getNameFunc()()); //"the window"
但不全是:
var name="the window"; var object={ name:"my object", getNameFunc:function(){ var that=this; return function(){ return that.name; }; } } alert(object.getNameFunc()()); //"my object"
6、使用閉包要小心
1)我們上面提到過閉包可以讓變量永久保存在內(nèi)存中,這會導(dǎo)致內(nèi)存消耗過大,所以使用閉包要謹(jǐn)慎,否則會帶來性能問題,IE中會導(dǎo)致內(nèi)存泄漏。
function assigmHandler(){ var element=document.getElementById("myelement"); element.onclick=function(){ alert(element.id); } }
此后element將永遠(yuǎn)駐留在內(nèi)存中。解決辦法就是在退出函數(shù)之前把不是用的局部變量刪除。
function assigmHandler(){ var element=document.getElementById("myelement"); var id=element.id; element.onclick=function(){ alert(id); } element=null; }
2)閉包會在父函數(shù)外部改變父函數(shù)的變量,比如上面的例子:
function outer() { var obj = { name: "xiaoming" } return { number: obj, getObj: function () { console.log(obj) } } } var people = outer(); people.getObj(); //Object {name: "xiaoming"} people.number.name = "xiaozhang"; people.getObj(); //Object {name: "xiaozhang"}
如果你把父函數(shù)當(dāng)作對象使用,把閉包當(dāng)作它的公用方法,把內(nèi)部變量當(dāng)作它的私有屬性,這時一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86516.html
摘要:溫馨提示作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命溫馨提示續(xù)本文將會成為一篇筆記類型的文章,記錄閉包具體的應(yīng)用方式溫馨提示再續(xù)本文存在錯誤,會慢慢改進的,請不要把我說的當(dāng)真在上一篇博文閉包不完全探索記錄閉包啥餡的中,對中 溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命溫馨提示-續(xù):本文(maybe)將會成為一篇筆記類型的文章,記錄閉包具體的應(yīng)用方式溫馨...
摘要:閉包一詞來源于以下兩者的結(jié)合要執(zhí)行的代碼塊由于自由變量被包含在代碼塊中,這些自由變量以及它們引用的對象沒有被釋放和為自由變量提供綁定的計算環(huán)境作用域。在以及及以上等語言中都能找到對閉包不同程度的支持。 溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命 閉包,好吃嗎 ? 第一次聽到這個詞,很不幸是在一次面試中,可想而知結(jié)果很細(xì)碎,從此閉包和跨域在我匱乏的前端知識中成為了...
溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命 這一切,源于阮大神博文學(xué)習(xí)Javascript閉包(Closure)- 阮一峰中的一道思考題 //問題1: var name = The Window; var object = { name : My Object, getNameFunc : function(){ return function(){ ...
摘要:單例模式主要是為了解決對象的創(chuàng)建問題。頁面中只放一個按鈕登錄實現(xiàn)得到登錄框元素綁定事件關(guān)閉彈框這里做登錄點擊頁面中的按鈕每次讓登錄框出現(xiàn)即可上面的代碼根據(jù)單例模式的使用構(gòu)造函數(shù)來實現(xiàn)的。 最近打算系統(tǒng)的學(xué)習(xí)javascript設(shè)計模式,以便自己在開發(fā)中遇到問題可以按照設(shè)計模式提供的思路進行封裝,這樣可以提高開發(fā)效率并且可以預(yù)先規(guī)避很多未知的問題。 先從最基本的單例模式開始。 什么是單例...
摘要:單例模式主要是為了解決對象的創(chuàng)建問題。頁面中只放一個按鈕登錄實現(xiàn)得到登錄框元素綁定事件關(guān)閉彈框這里做登錄點擊頁面中的按鈕每次讓登錄框出現(xiàn)即可上面的代碼根據(jù)單例模式的使用構(gòu)造函數(shù)來實現(xiàn)的。 showImg(https://segmentfault.com/img/bVbiE4g?w=568&h=450);最近打算系統(tǒng)的學(xué)習(xí) Javascript 設(shè)計模式,以便自己在開發(fā)中遇到問題可以按照...
閱讀 3952·2021-11-16 11:50
閱讀 949·2021-11-11 16:55
閱讀 3675·2021-10-26 09:51
閱讀 874·2021-09-22 15:03
閱讀 3444·2019-08-30 15:54
閱讀 3273·2019-08-30 15:54
閱讀 2485·2019-08-30 14:04
閱讀 928·2019-08-30 13:53