摘要:首先變量對于一個程序來說是一個很重要的角色那么問題來了這些變量存在哪里程序用到的時候如何找到變量呢所以需要一套規則來存儲變量方便之后再找到這套規則就成為作用域是一門編譯語言對于來說大部分情況下編譯發生在代碼執行前的幾微妙的時間內對于參與到一
首先,變量對于一個程序來說是一個很重要的角色, 那么問題來了 這些變量存在哪里,程序用到的時候如何找到變量呢?
所以需要一套規則來存儲變量方便之后再找到 這套規則就成為作用域.
js是一門編譯語言,對于js來說 大部分情況下編譯發生在代碼執行前的幾微妙的時間內,
對于參與到一個程序 : var a = 2; 處理的時候,
引擎 : 從頭到尾負責整個js程序的編譯和執行過程
編譯器: 負責的是語法分析和代碼生成
作用域: 負責收集并維護所有聲明的變量組成的一系列查詢,并實施一套非常嚴格的規則,最后確定當前執行的代碼對于這些變量的訪問權限
對于 var a = 2; 來說
首先編譯器會先詢問作用域是否已經有一個該名稱a的變量存在同一個作用域的集合中 ,如果有了 編譯器就會忽略否則 則會要求作用域在當前作用域集合中聲明一個新的變量 名稱為a;
然后編譯器生成代碼來進行a=2 的復賦值操作, 到了引擎工作的時候了 首先會先在作用域中查找a這個變量,如果有,引擎就會對變量a進行LHS查詢(LHS查詢是試圖找到變量本身然后進行賦值操作(等號左邊left) | RHS查詢是指非等號左邊的查詢 即要取到某個變量的指),對a進行賦值操作.如果找不到這個變量就會拋出異常了.
(
這里補充一下引擎的LHS查詢和RHS查詢 : 例如 var b=a; return a+b 這里的 LHS查詢有: b=...
RHS查詢有 =a; a...; b...; 對于變量沒有聲明的情況下,兩個查詢的行為是不一樣的, 對于 b=a
時,對b=進行LHS查詢 會一直向上作用域查找該變量 如果在最頂層還沒有找到 那么就會在最頂層創建一個b變量(非嚴格模式下) ,
而對于=a進行RHS查詢時,如果在所有作用域中找不到該變量就會拋出ReferenceError異常.
)
了解了js工作機制之后,那么對于 "聲明提升" 就會恍然大悟了,
例如:
foo(); function foo(){ console.log(a) //undefined var a= 2; } //首先編譯器先定義聲明foo 和 作用域中的a 然后才會到引擎執行代碼進行賦值操作,所以才有了以上的輸出, 這種效果即是"聲明提升"
意味著無論作用域中的聲明出現在什么地方,都會在代碼執行前(編譯階段)進行首先處理,想象成所有的聲明都會被移動到各自作用域的頂端,===>即成為 我們所說的提升.
對于作用域有了深入理解了之后 接下來說一說作用域閉包
網上對于閉包的定義太多了 總的來說 閉包實際上就是:
無論通過任何手段將內部函數傳遞到所在的此法作用域以外,它都會持有對原始定義作用域的引用,無論在任何處執行這個函數都會使用閉包,
所以說平時寫的代碼中
很多就是閉包只是自己沒有發現而已,本質上無論何時何地,如果將(訪問他們各自此法作用域的)函數當做第一級的值類型并到處傳遞,你就會看到閉包在這些函數中的應用了.
在定時器,事件監聽器,ajax請求,web workers..等任務中只要用了回調函數 其實就是在使用閉包!
幾個閉包的例子: 1. function foo(){ var a =2; function baz(){ consolo.log( a ) // 2 } bar(baz) } function bar(fn){ fn(); } foo(); //把內部函數baz 傳遞給bar 當調用這個內部函數時,它涵蓋的foo()內部作用域的閉包就可以觀察到了,因為能訪問到a. 2. function wait(message){ setTimeout(function timer(){ console.log(message) },1000) } wait("hello,closure") 3. function setBot(name,selector){ $(selector).click(function activator(){ console.log("activating:" + name) }) } setBot("test1","#bot1"); setBot("test2","#bot2");
ok,還有其他的代碼模式利用了閉包的作用,表面上看似乎和回調函數無關,這就是 模塊
對于模塊模式,需要的兩個必要條件就是
必須有外部的封閉函數,該函數必須被至少調用一次,(每次調用都會創建一個新的模塊實例)
封閉函數必須返回至少一個內部函數,這樣內部函數才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態!
舉個例子(單例模式) var foo = (function Moudle(){ var something = "oye"; var other = [1,2,3]; function dosomething(){ console.log(something); } function doother(other){ console.log(other.join("!")); } return { doSomething : dosomething, doother:doother } })(); foo.dosomething(); //oye foo.doother(); // 1!2!3 //模塊也是普通的函數 所以也可以接受參數.
模塊模式的另一個簡單強大的用法是命名將要作為公共API返回的對象:
var foo = (function moudel(id){ function change(){ //修改公共API public.one = two; } function one(){ console.log(id); } function two(){ console.log(id.toUpperCase()); } var API = { change:change, identify:one } return API; })("foo moudel") foo.identify(); //foo moudel; foo.change(); foo.identify(); // FOO MOUDEL; //通過在模塊實例的內部保留對公共API對象的內部引用,可以從內部對實例進行修改,包括添加或者刪除方法和屬性,以及修改值.
對于現代的模塊機制
本質上都是將這種模塊定義封裝進一個友好的API
//模塊管理工具,MyModules var MyModules = (function Manager() { var modules = {}; function define(name, deps, impl) { for (var i=0; i未來的模塊機制
即ES6為模塊增加的以及語法支持, 在通過莫魁岸系統進行加載時,ES6會將文件當做獨立模塊來處理.每個模塊都可以導入其他模塊或者特定的API成員,同樣也可以導出自己的API成員.
(
因為函數的模塊并不是一個能被靜態識別的模式(編譯器無法識別,)他們的API語義只有在運行時才被考慮進來.
相比之下 ES6模塊API是靜態的,編譯器知道這一點 然后在編譯器會對模塊導出的API或者成員的引用做一次檢查是否存在,不存在就會拋出早期的錯誤 不會等到運行期在動態解析
)bar.js function hello(who){ return "我是"+who } export hello; foo.js import hello from "bar" var new = "marry"; function newHello(){ console.log( hello(new).toUpperCase(); ) } export awesome; baz.js module foo from "foo"; module bar from "bar"; console.log(bar.hello("lil")) //我是lil foo.newHello(); //我是MARRY; // import 可以將一個模塊的一個或者多個API導入到當前作用域中,并分別綁定在一個變量上. module會將整個模塊的API導入并綁定. export會將當前模塊的一個標識符(變量 函數) 導出為公共APII總結:
當函數可以記住并且能訪問所在語法作用域,即使函數實在當前作用域之外執行,這時候就產生了閉包.
對于模塊首先必須有外部的封閉函數,該函數必須被至少調用一次,(每次調用都會創建一個新的模塊實例)
封閉函數必須返回至少一個內部函數,這樣內部函數才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97576.html
摘要:這篇文章總結下之前看的文章和自己在工作中遇到的坑,純手寫的,有什么寫的不對的請多多提出修正哈變量提升何為變量提升里面的變量在聲明之前就可以使用,因為該聲明已經被提升至該作用域函數或全局的頂部直接上代碼和都會變量提升優先級上面可理解為函數這時 這篇文章總結下之前看的文章和自己在工作中遇到的坑,純手寫的,有什么寫的不對的請多多提出修正哈 變量提升 何為變量提升?js里面的變量在聲明之前就可...
摘要:大名鼎鼎的閉包面試必問。閉包的作用是什么。看到閉包在哪了嗎閉包到底是什么五年前,我也被這個問題困擾,于是去搜了并總結下來。關于閉包的謠言閉包會造成內存泄露錯。閉包里面的變量明明就是我們需要的變量,憑什么說是內存泄露這個謠言是如何來的因為。 本文為饑人谷講師方方原創文章,首發于 前端學習指南。 大名鼎鼎的閉包!面試必問。請用自己的話簡述 什么是「閉包」。 「閉包」的作用是什么。 首先...
摘要:類型是提供的引用類型之一,通過可需變更創建對象。調用自身的函數被稱之為遞歸函數。想要解決上述遞歸函數的問題,可以使用對象屬性替換具體的函數名。保護貢獻的局部變量。 Function類型 概述 Function與函數 函數是這樣的一段JavaScript代碼,她只定義一次,但是可能被執行或調用多次。Function類型是JavaScript提供的引用類型之一,通過Function可u需變...
摘要:可見裝飾器改變了函數的功能。裝飾器除了改變函數功能之外還有一個特性是,函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時運行。 什么是裝飾器 裝飾器是什么,簡單來說,裝飾器可以改變一個函數的行為,比如原本有一個函數用來計算菲波那切數列,我們給這個函數加個計算執行時間的裝飾器,這樣原來的函數不僅能夠計算菲波那切數列,而且還可以輸出計算花費了多少時間。 在Python中,有幾個很...
閱讀 725·2021-11-17 09:33
閱讀 3757·2021-09-01 10:46
閱讀 1751·2019-08-30 11:02
閱讀 3280·2019-08-29 15:05
閱讀 1396·2019-08-26 11:39
閱讀 2272·2019-08-23 17:04
閱讀 1973·2019-08-23 15:43
閱讀 1371·2019-08-23 14:12