摘要:閉包閉包,目前還沒有統一的定義。展開這個對象果然是世界上最好的瀏覽器,給我們展示了閉包中訪問的變量。模塊化的始祖據筆者所了解,模塊化就是借用閉包來實現的。所以我們在開發過程用要慎用閉包。
標題為什么叫日了哈士奇?因為閉包這個東西已經在我腦海里縈繞了很久,大概有多久呢?(掰手指頭和腳指頭ing....) 大概是筆者從事前端工作的第一個月開始吧......仍記得那個時候還請教了公司的大神,不過只怪當時腦袋不好使,反正就是沒聽懂啊喂!不過最近項目沒那么忙,就回頭研究這個前端亙古不變得話題之一:閉包。誠然,閉包對于JavaScript初學者而言理解起來稍許有點吃力,不過我相信即使是初學者看了本篇博客,也會被閉包有更深的認識(“王婆賣瓜,自賣自夸”),hahah...廢話不扯了,趕緊開始吧。
話題引入在開始介紹閉包之前呢,筆者先墨跡下。大家先來思考這樣一個問題:
如何從函數A外部訪問函數A內的變量?
不了解閉包的朋友可能會認為這是一個愚蠢得像土撥鼠系列的問題,就是一個字:扯淡 (手動滑稽)。即使這樣子,筆者還是不知廉恥得貼出上一篇博客的地址,因為這篇博客對解決這個問題有很大的幫助。下面就一起思考如何回答上述的問題:
根據上篇博客的描述,要想訪問一個變量,那么必定要在這個變量的作用域內訪問;其次,對于訪問函數中的變量,那只能在函數中做點事(手)情(腳),比如這樣:
function closure() { let name = "Husky"; let age = 2; //access variable }
那么既然已經在函數中訪問到了,那又如何才能實現在函數外訪問到呢?答案是肯定是,只要再做點事(手)情(腳)就好了,不過先不急著思考怎么辦,下面給大家形象化一個非(喪)常(心)有(病)趣(狂)的情景:
隔壁老王啊是個房東,今天有個美女要租他的房子。美女真是一(胸)身(大)正(臀)氣(翹),于是老王想借此機會觀(偷)察(窺)一番。無奈每天晚上房間的門窗都被關得嚴嚴實實根本沒從下眼,老王就偷偷在里面安裝了攝像頭,然后就肆無忌憚了...(手動滑稽)
情景描述完了,不過朋友們不要想入非非,畢竟筆者一身正氣啊喂!
改一下上面的代碼來將上述情景表達出來:
function Room() { let beauty = "如花"; //攝像頭 }
那么攝像頭可以在房間里捕(訪)捉(問)房(函)間(數)內(體)的影(變)像(量),同時還能把捕捉到的情景傳回到老王的屏幕上。因此可以聯想到,我們在函數中放置一個對象然后在對象中訪問變量并且把這個對象return出去,我們再接收返回回來的對象后不就可以在外面訪問變量了嘛!Bingo...就是這樣。
俗話說,JavaScript世界中萬物皆對象(函數也是對象)。所以我們可以這樣補充上面的代碼:
function Room() { let beauty = "如花"; //攝像頭 let camera = function() { return beauty; } }
這樣我們就能獲取到一個函數,相當于攝像頭的信號線,通過這個就可以獲取到影像咯:
function Room() { let beauty = "如花"; //攝像頭 let camera = function() { return beauty; } return camera`請輸入代碼`; } let camera = Room(); let beauty = camera(); console.log(`老王看到 ${beauty} 啦`);
看下運行結果:
然后我們就幫助老王如愿以償得看到了如花并且繼續每晚不可描述的事。(看我一臉正氣...)
說到這,閉包這個玩意兒已經浮出水面。
閉包閉包,目前還沒有統一的定義。單就筆者的理解就是:閉包是一個體系,由函數體中的變量和訪問該變量的函數組合而成。
對應上述的代碼就是:beauty 和 camera
閉包只是這類體系的名字,其英文名是Closure;閉包其實并沒有關閉的意思,相反它還向外暴露內部的變量只不過是通過一定的約束方式(函數)。舉個例子:
function closure(){ let fronted=["js","css"]; return function(){ return fronted; } } let fronted = closure()(); <----運行兩次,分別運行closure和返回的匿名函數 console.log(fronted); fronted.push("html"); console.log(fronted);
我們在函數中聲明一個數組并且初始化它,最后通過匿名函數(推薦使用匿名函數)返回。這樣我們可以在函數外面獲得內部的數組并且可以進行一些操作,如上運行結果如下:
Chrome瀏覽器是如何來識別一個閉包的不同的瀏覽器對閉包也有不同的理解。下面筆者使用世界上最好的瀏覽器Chrome瀏覽器來演示下它是如何去識別一個閉包的,代碼還是用的上面那個代碼:
首先我們要打兩個斷點
第一步運行,并且請觀察截圖中紅框框的地方
第二步運行,并且也請觀察截圖中紅框框的地方,比較和上一步的不同
沒錯,多了一個“Closure”對象 并且指向了(closure)這個函數,說明到這里Chrome已經識別出了這是一個閉包。展開這個對象:
果然是世界上最好的瀏覽器,給我們展示了閉包中訪問的變量。神器啊有木有...
閉包的原理說了那么多,那么閉包的原理到底是什么呢?且聽我慢慢道來。
看過我上一篇博客的朋友都知道,想訪問一個變量那么必須要處在這個變量的作用域中。比如fronted這個變量在closure函數中定義,那么closure函數中的匿名函數就可以訪問這個fronted變量。因為只能訪問父域或者同域的變量。當匿名函數在自己內部訪問了這個變量的時候就相當于持有了該變量的引用,所以當和這個匿名函數被 return 出去的時候,仍可以訪問該變量。
技術的出現時為了解決一類問題,閉包能用來干什么呢?
隱藏變量
通過閉包,我們可以向外界輸出一個變量,不過并不是直接暴露出去而是通過類似于接口的函數向外暴露,這樣既可以在外界訪問這個變量又保證了這個變量不會被破壞。
模塊化的始祖
據筆者所了解,JavaScript模塊化就是借用閉包來實現的。通過定義一個module變量,并且向外暴露相關操作module的方法,來實現導入和導出。
使用閉包的注意點通常來說,當一個函數運行結束后,函數中的變量內存會被回收掉,但是上一篇博客特地強調了閉包并不會這樣。實際上如例子所示,即使closure函數運行完了,但是它返回的匿名函數中仍持有變量fronted的引用,因此這個變量會一直存在于內存中并且不會被回收(初非人為解除引用)。因此可以預見性得猜到,如果我們在程序中大量得使用閉包,那么大量的變量存在于內存中而占用前端內存資源會導致性能的下降。所以我們在開發過程用要慎用閉包。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96455.html
摘要:回調地獄的問題在于寫法過于繁瑣不夠優雅代碼維護炒雞蛋疼,所以一直被前端程序猿所詬病,尤其是維護類似代碼的時候簡直日了一群哈士奇。,對象狀態以和為分水嶺。方法返回一個帶有拒絕原因參數的對象摘自對的解釋。并且返回的也是一個對象。 這是一段旁白 異步虐我千百遍,我待異步如初戀!!做前端的同學做異步肯定都不陌生。因為JavaScript是單線程語言(也就是說不支持多線程編程,這不是廢話么啊喂!...
摘要:關于有人說我用刪除這個屬性不就好了之后打印發現它還是一只哈士奇。如下的解釋如下操作符會從某個對象上移除指定屬性。 javascript-Object-Property ? javascript-對象的屬性的延伸學習 showImg(https://segmentfault.com/img/bVNH2S?w=640&h=640); 前言 在學習vue數據綁定的較底層原理時,被setter...
摘要:面向對象面向對象編程的全稱為簡稱。面向對象編程是用抽象方式創建基于現實世界模型的一種編程方式。面向對象編程可以看做是使用一系列對象相互協作的軟件設計。面向對象編程的三個主要特征是封裝繼承多態。 面向對象 面向對象編程的全稱為Object Oriented Programming,簡稱OOP。面向對象編程是用抽象方式創建基于現實世界模型的一種編程方式。面向對象編程可以看做是使用一系列對象...
摘要:深入系列第八篇,介紹理論上的閉包和實踐上的閉包,以及從作用域鏈的角度解析經典的閉包題。定義對閉包的定義為閉包是指那些能夠訪問自由變量的函數。 JavaScript深入系列第八篇,介紹理論上的閉包和實踐上的閉包,以及從作用域鏈的角度解析經典的閉包題。 定義 MDN 對閉包的定義為: 閉包是指那些能夠訪問自由變量的函數。 那什么是自由變量呢? 自由變量是指在函數中使用的,但既不是函數參數也...
閱讀 2736·2021-10-09 09:44
閱讀 3549·2019-08-30 15:54
閱讀 2159·2019-08-30 14:16
閱讀 2789·2019-08-30 13:09
閱讀 824·2019-08-30 13:08
閱讀 1279·2019-08-29 16:29
閱讀 1661·2019-08-26 13:57
閱讀 1924·2019-08-26 13:53