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