javascript
(转)JavaScript: 零基础轻松学闭包(1)
- 閉包是什么?
初學javascript的人,都會接觸到一個東西叫做閉包,聽起來感覺很高大上的。網上也有各種五花八門的解釋,其實我個人感覺,沒必要用太理論化的觀念來看待閉包。
事實上,你每天都在用閉包,只是你不知道罷了。
比如:
var cheese = '奶酪';var test = function(){alert(cheese); }?
OK,你已經寫了一個閉包。
- 函數也是一個數據類型
變量 cheese 是在全局作用域中的一個變量,當你創建了一個 test 函數,那么,test 和 cheese 就共享一個全局作用域。
你要額外明白的一點是,在js中,函數和變量本質上是一個東西。函數也是一個數據類型。
從上面的定義中也能看出來這一點。你要是不相信的話,我們來看一下咯。
alert(cheese); alert(test);讓我們再來看看 test 和 cheese各是什么類型:
alert(typeof test); alert(typeof cheese);看到了吧,只是類型不同而已,他們都是數據類型。
唯一的不同點就是,函數類型的 test 可以擁有自己內部邏輯,而string類型的 cheese 只能存放一個字面值,這就是區別,僅此而已。
一目了然了,唯一不同的就是普通變量是字面值一樣的存在,而函數需要打個括號才能執行而已。
你看,我現在打一個括號:
test();打了括號,才會執行函數里面的邏輯。
- 作用域
讓我們回到閉包,現在將之前的代碼做一個小小的變動:
var cheese = '奶酪'; var test = function(){alert(cheese); }function test2(){var cheese = null;test(); }test2();?
那么,你覺得現在 alert 出來的是 null 還是奶酪呢?
思考一下。。。
對的,彈出來的還是奶酪。
之前已經說過了,函數 test 和 變量 cheese 同處于一片藍天下 -- 同一個作用域。
函數 test 和 變量 cheese 共同享有的作用域叫做全局作用域,就好像地球一樣,我們所有的人都享有這個地球,能夠在這里呼吸,吃飯,玩耍。
對test而言,他能訪問到的作用域只有它本身的閉包和全局作用域:
Paste_Image.png也就是說,正常情況下他訪問不到其他閉包里的內容,在 test2 里面定義的變量跟它沒有半毛錢關系,所以彈出來的 cheese 依舊是全局作用域里的 cheese。
函數可以創造自己的作用域。
我們剛才定義了一個 test 函數,{ } 包裹起來的部分就形成了一個新的作用域,也就是所謂的閉包。
其實你深刻了解了作用域的原理后,閉包也就理解了。
就好比地球是一個全局作用域,你自己家的房子是一個函數,你的房子是私人空間,就是一個局部作用域,也就是你自己建了一個閉包!
你透過窗戶可以看見外邊的景色,比如院子里的一棵芭蕉樹,你于是通過眼鏡觀察看到了芭蕉樹的顏色,高度,枝干的粗細等等。
這一棵芭蕉樹相當于一個全局變量,你在自己的閉包內可以訪問到它的數據。
所以,在這個例子中,test 就是一個房子,在里面可以通過窗戶訪問到全局作用域中的奶酪 —— 變量 cheese。
也就是說,cheese 在被 test 訪問到的時候,就進入了它的閉包。
這樣解釋,你是否覺得好理解一點呢?
現在你是否可以理解一開始我說,閉包這東西其實我們天天都在用的意思了呢?
我們給出閉包的第一個注解:
1. 閉包就是在函數被創建的時候,存在的一個私有作用域,并且能夠訪問所有的父級作用域。
回到剛才的例子:
var cheese = '奶酪'; var test = function(){alert(cheese); }function test2(){var cheese = null;test(); }?
在這個例子中,test 和 test2 各自享有一個作用域,對不對?而且他們互相不能訪問。比如,我在 test 中定義的一個變量,test2就無法直接訪問。
var test = function(){var i = 10; }function test2(){alert(i); }test2();?
像這樣,一旦執行 test2 函數,編譯就不通過,因為在 test2的閉包內,根本找不到變量 i 。它首先會在自己的閉包內尋找 i,找不到的話就去父級作用域里找,這邊的父級就是全局作用域,很遺憾,還是沒有。這就是所謂的作用域鏈,它會一級一級往上找。如果找到最頂層,還是找不到的話,就會報錯了。
在這里,還有一個需要注意的點就是:如果某一個閉包中對全局作用域(或父級作用域)中的變量進行了修改,那么任何引用該變量的閉包都會受到牽連。
這的確是一個需要注意的地方。
舉個例子
var cheese = '奶酪';var test = function(){cheese = '奶酪被偷吃了!' }function test2(){alert(cheese); } test(); test2();?
結果是:
Paste_Image.png很有趣,是不是呢?
當我們在定義一個函數,就產生了一個閉包,如果這個函數里面又有若干的內部函數,就是閉包嵌套著閉包。
像這樣:
function house(){var footBall = '足球';/* 客廳 */function livingRoom(){var table = '餐桌';var sofa = '沙發';alert(footBall);}/* 臥室 */function bedRoom(){var bed = '大床';}livingRoom(); }house();?
函數house是一個閉包,里面又定義了兩個函數,分別是livingRoom客廳,和bedRoom臥室,它們各自形成一個自己的閉包。對它們而言,父級作用域就是house。
如果我們希望在客廳里踢足球,在livingRoom函數執行的時候,它會先在自己的閉包中找足球,如果沒找到,就去house里面找。一層一層往上找,直至找到了為止。當然,這個例子可能不是很恰當。但起碼展示了作用域,閉包之間的聯系。
再說明一下, 閉包就是在函數被創建的時候,存在的一個私有作用域,并且能夠訪問所有的父級作用域。因此,從理論上講,任何函數都是一個閉包!
作者:剽悍一小兔
鏈接:https://www.jianshu.com/p/6f5833e261ac
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。
轉載于:https://www.cnblogs.com/dragonwave/p/9273580.html
總結
以上是生活随笔為你收集整理的(转)JavaScript: 零基础轻松学闭包(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 筹码集中度数值怎么看
- 下一篇: Spring MVC普通类或工具类中调用