JavaScript文法之詞法範圍

來源:互聯網
上載者:User

標籤:eps   java   turn   func   modules   交流   括弧   賦值   綁定   

關於js基本的包括詞法範圍和模組基礎的總結。 1 編譯器---範圍---引擎 編譯器負責分析及代碼產生,範圍負責維護好所有的標識符(變數)組成的一系列查詢,引擎負責按照範圍規定的規則執行代碼。 所以,範圍相當於中介,先是編譯器編譯,範圍維護,然後引擎按照範圍來執行。所以雖然js是解釋型語言,但實際上仍然是先編譯再執行。 引擎在執行時採取LHS查詢和RHS查詢。按我理解,LHS查詢就是查詢“容器”,即裝載資料的變數。RHS查詢的是變數值本身。  2 遍曆嵌套範圍鏈的規則 引擎從當前知道執行範圍開始尋找變數,如果找不到就向上一級尋找。當抵達最外層的全域範圍時,無論是否找到,尋找過程都會停止。  3 js遵循的是詞法範圍。 一個函數的範圍取決於其定義時所處的定義域,而與其在哪裡如何被調用無關。(函數申明提升,那也是在它定義時所處的範圍中提升,所以仍在同一個範圍中,沒有影響) 為避免函數汙染所在的範圍(比如說一個函數只需要運行一次,之後就不需要了),那麼可以用(function foo(){})(),即IIFE 除了函數,還可以用{let a =1;}即let和大括弧來顯式建立塊範圍。其中,let的作用就是讓let 的變數只能在它所處的這個塊中使用,塊以外的範圍用不了。 為變數顯式聲明塊範圍,即把某些變數放進{}裡,用let聲明,並對變數進行本地綁定,這樣當這個變數被使用完畢後,資料會被記憶體回收。什麼意思呢?就是說把一個資料主動放入塊範圍中,即外面不能用,這樣記憶體回收機制就知道,這個資料一旦被用完,塊範圍外面的範圍就再也用不到(也用不了)它了,所以可以直接被記憶體回收。這樣減少記憶體佔用。  4 關於提升 包括變數和函數在內的所有聲明都會在編譯階段被處理,即聲明提升。而賦值或其他運行邏輯會留在原地,等待執行階段。之前已經知道,js是先編譯後執行,所以可以知道是先有聲明,後有賦值。函式宣告和變數聲明都會被提升,但是函式宣告會首先被提升,即被提升到各自範圍最頂部,超過變數聲明。  5 閉包 由於js是遵循詞法範圍的,所以函數在別的某個地方(不在其所在的範圍中)被調用(以將函數本身return出去的方式或者別的無論什麼方式),而執行的時候是遵循其範圍的,這樣就形成了閉包。不好理解的地方是,函數整個被當做實值型別並匯出傳遞,無論傳遞到哪裡去調用,由於遵循詞法範圍,運行時還是依據定義該函數的位子所在的定義域。或者可以理解為,function aa(){.....} 這整個函數最開始定義在哪裡,就遵循那裡的範圍。當函數可以記住並訪問所在的詞法範圍,即使函數是在當前詞法範圍之外執行,這時就產生了閉包。只要使用了回呼函數,實際上就是在使用閉包。(原因是這個函數整個在某個非同步參數中被定義,而在別的線程中被調用,那麼運行時所依據的當然是定義時的位置所處的範圍鏈) for (let i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 );}這是閉包和塊範圍的聯手。閉包指的是setTimeout非同步,塊範圍是指用let。在for迴圈裡調用let即說明每次的i都是重新聲明的。 其實,閉包就是函數定義在範圍A上,而在範圍A外的某個範圍調用。  6 關於模組 模組就是利用了閉包。按我理解,就是一個函數,裡面先寫好內建函式和變數,即閉包,然後將函數return出來。每次先調用外層函數,獲得裡面的函數,在外面調用。 模組模式必須具備兩個條件:1 必須有外部的封閉函數,該函數必須至少被調用一次(每次調用都會建立一個新的模組執行個體)2 封閉函數必須返回至少一個內建函式,這樣內建函式才能在私人範圍中形成閉包,並且可以訪問或者修改私人變數。 模組的例子:var MyModules = (function Manager(){    var modules = {};     function define(name, deps, impl){        for(var i=0;i<deps.length;i++){            deps[i] = modules[deps[i]];        }        modules[name] = impl.apply(impl,deps);        console.log(modules);    }     function get(name){        return modules[name];    }     return {        define:define,        get:get    }})(); 首先,這是一個叫做Manager的模組創造器,立即調用後將API介面暴露出來賦值給MyModules,這樣就只執行一次,即為單例模式。這個Manager模組裡有一個modules,這是放各個模組的對象。define即封裝函數用來定義新的模組。傳入3個參數,分別是name,即新模組的名字;deps,即該模組所需要依賴的其他模組(注意,只是該新模組定義時所需要的模組而不是所有模組,用數組的方式傳入,數組裡面的每一項是所需的相依模組的名字);impl,即新模組的定義。define函數先進行一個遍曆,目的是將deps中的模組從modules中取出,放入deps中。modules[name] = impl.apply(impl,deps);意思是將impl的運行上下文綁定到自己的函數裡面,傳入依賴deps並運行,將結果儲存在以傳入的name命名的modules中。(注,這裡用apply函數,我個人認為是利用了apply函數的一個很方便的特性,那就是可以將數組直接拆成一個個元素傳入函數)接下來是調用: MyModules.define(‘bar‘,[],function(){    function hello(who){        return ‘nihao ‘+ who;    }    return {        hello:hello    }}); MyModules.define(‘bye‘,[],function(){    function bye(who){        return ‘bye ‘+who;    }    return {        bye:bye    }}); MyModules.define(‘foo‘,[‘bye‘,‘bar‘],function(){    var who= ‘Mike‘;    var args = arguments;    function awesome(){        console.log(args[0].bye(who)); //用apply運行函數時可以用arguments來擷取參數,這樣可不必列出所有形參        console.log(args[1].hello(who));    }    return {        awesome:awesome    }}); var foo = MyModules.get(‘foo‘);foo.awesome();// bye Mike   nihao Mike   歡迎互相交流,互相學習。前端開發QQ群:711357426

JavaScript文法之詞法範圍

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.