摘要:把這兩個因素結合起來,就能通過把變量包裹在匿名函數中而對其加以保護。執行完后雖然已經變成數組的長度,但是匿名函數每次立即執行的時候傳入的參數是相應的四函數定義內調用本身在中被廢棄了。
一 閉包和作用域
閉包是一個受到保護的變量空間,由內嵌函數生成。JavaScript具有函數級的作用域。這意外著定義在函數內部的變量在函數外部不能被訪問。JavaScript的作用域又是詞法性質的。這意味著函數運行在定義它的作用域中,而不是在調用它的作用域中。把這兩個因素結合起來,就能通過把變量包裹在匿名函數中而對其加以保護。(引自《JavaScript設計模式》)
var i = 100; function makeCounter() { var i = 0; // makeCounter的私有變量 return function() { console.log(++i); } //該函數運行的環境是makeCounter的作用域 } var counter = makeCounter(); // counter即makeCounter的內嵌函數,運行時獲取的i來源于makeCounter作用域中的i counter(); // 輸出: 1 而非 101 –>因為makeCounter返回的內嵌函數能獲取i,所以也稱為makeCounter的特權函數。 counter(); // 輸出: 2 i; // 輸出: 100 –>說明makeCounter內的i不能被調用
二 () 調用函數
(1)function foo() {} 和 var foo = function() {},foo都是這里function(){}的引用,調用時只需要直接foo()。但如果直接將()放在function(){}后面則會觸發語法錯誤。
function() {..}() // SyntaxError: Unexpected token(
原因:當解析器遇到function關鍵字時,默認將其視為一個函數聲明(function declaration),而不是一個函數表達式(function expression)。如果不顯式告訴解析器將其視為一個函數表達式,則會視其為一個函數聲明缺少名字的語法錯誤。
(2)針對上面語法錯誤,給函數加個名稱并加()執行,會觸發另外一個語法錯誤:
function foo() {….} () ; // SyntaxError: Unexpected token )
原因:()放在表達式后面表示這個表達式是個函數并將要被調用,而()放在statement(函數聲明也是個statement)后面則是用來與前一個statement分隔,僅僅是一個分組運算符(用在控制運算優先級的,即: 1 + 2 * ( 3 + 4 )這里括號的作用 )
修正:()作為分組運算符時,需要包含一個表達式,所以簡單加個表達式 (1)。
function foo() {…}(1) ; //不會報錯了,這樣的寫法其實等同于下面 function foo() {…} // 所以foo在這里并沒有被調用,而僅僅是個聲明而已。 (1)
(3)上面的修正只是解決了語法錯誤,但實際上并沒有達到我們的期望:讓函數立即執行。最常用的方法是將其包在()內。因為在JavaScript中,()只能包含表達式而不能是語句statement。
(function() {..}()) 或者 (function() {..})()
(4)其他方法:原理都是令解析器認識到()前是一個表達式
var x = function() { return 1; }(); true && function() { .. } (); 0, function() {..} () ! function() {..} () ~ function() {..} () + function() {..} () – function() {..} ()
三 利用閉包保存狀態
(1)下面例子給元素添加事件監聽,結果每個a點擊后輸出的都是elmes數組的長度。
原因:for執行后的每個elems的點擊事件函數中綁定的是 j ,當點擊時輸出的 j 確確實實就是 j 在for運行之后的值。
var elems = document.getElementsByTagName(‘a’); for (var j = 0; j < elems.length; j++) { elems[j].addEventListener(‘click’, function(e) { e.preventDefault(); console.log (j); }, false); }
(2)下面例子利用立執行函數,將 j 鎖定。
for執行完后 j 雖然已經變成elems數組的長度,但是匿名函數每次立即執行的時候傳入的參數是相應的 j
var elems = document.getElementsByTagName(‘a’); for (var j = 0; j < elems.length; j++) { (function( lockedIndex ) { elems[j].addEventListener(‘click’, function(e) { e.preventDefault(); console.log(lockedIndex); }, false); })(j); }
四 函數定義內調用本身
function foo() { foo(); } var foo = function() { arguments.callee(); } // arguments.callee 在ECMAScript5中被廢棄了。
五 參考
immediately-invoked-function-expression
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86042.html
摘要:前言大家學的時候,經常遇到自執行匿名函數的代碼,今天我們主要就來想想說一下自執行。其實,前面兩個例子里的變量,也可以換成,因為和外面的不在一個作用于,所以不會出現問題,這也是匿名函數閉包的威力。 前言 大家學JavaScript的時候,經常遇到自執行匿名函數的代碼,今天我們主要就來想想說一下自執行。 在詳細了解這個之前,我們來談了解一下自執行這個叫法,本文對這個功能的叫法也不一定完全對...
摘要:作用域和閉包以及自執行函數作用域作用域分為種全局作用域全局作用域就是在的任何位置都能訪問過函數作用域只能在函數里面調用的稱之為函數作用域閉包嵌套在函數里面的函數及周邊的變量叫閉包閉包存在的問題是周邊變量不會被釋放,常駐內存中閉包的缺點消耗內 作用域和閉包以及自執行函數 作用域 作用域分為2種 1、全局作用域 全局作用域就是在js的任何位置都能訪問過 2、函數作用域 只能在函數里面調用的...
摘要:打開源碼,首先你會看到這樣的代碼結構這是一個自調用匿名函數。模式,是自執行函數的高級模式,可以非常方便的在各個匿名閉包中以全局對象調用閉包函數。 打開jQuery源碼,首先你會看到這樣的代碼結構: (function(window,undefined ){ // })(); 這是一個自調用匿名函數。什么東東呢?在第一個括號內,創建一個匿名函數;第二個括號,立即執行 為什么要創建這樣一個...
摘要:但是到底是如何找到對應的函數的呢今天,我們來一起尋找答案函數分類首先,我們先回顧一下的函數分類,函數包含用戶自定義函數內部函數匿名函數等多種類型。用戶自定義函數和內部函數編譯完成后會將函數名注冊到全局函數列表中。 對于PHPer而言,我們通常會把常用的功能封裝成一個函數來進行復用,以提升開發效率。但是php到底是如何找到對應的函數的呢?今天,我們來一起尋找答案~ 函數分類 首先,我們先...
摘要:組件化開發小程序在未出現組件之前,要重用的話,只能簡單復制粗暴黏貼組件化開發的優勢可復用代碼分離,可維護更重要定義組件先創建文件夾用于存放組件,然后再創建組件文件夾注意組件的文件名并不是組件名,而頁面文件名是頁面名,組件名是引用時才確定的引 組件化開發 小程序在未出現組件之前,要重用的話,只能簡單(復制)粗暴(黏貼) 組件化開發的優勢: 1、可復用(wxml/wxss/js) 2、代...
摘要:為了更加方便的處理異步操作問題,現在最新的前端框架生態都開始用上了和,有的甚至已經開始使用最新的語法了,這兩樣都是基于自動執行的原理。這里就簡單理解下自執行及語法原理一函數函數指的是能將執行結果傳入回調函數,并將該回調函數返回的函數。 為了更加方便的處理異步操作問題,現在最新的前端框架生態都開始用上了Generator和yield,有的甚至已經開始使用最新的async、await語法了...
閱讀 3351·2021-10-13 09:40
閱讀 2586·2021-10-08 10:17
閱讀 3989·2021-09-28 09:45
閱讀 922·2021-09-28 09:35
閱讀 1805·2019-08-30 10:51
閱讀 2898·2019-08-26 12:11
閱讀 1645·2019-08-26 10:41
閱讀 3091·2019-08-23 17:10