本文主要和大家分享JS之立即執行函數講解,所謂立即執行函數(Immediately-Invoked Function Expression),即在函數表達式之後加()就可以使函數自執行。注意:不能再函數宣告後加括號()。
(function foo(){/* code */}()); //正确,推荐这样使用 (function foo(){/* code */})(); //正确,这样可以 var foo = function foo(){/* code */}(); //正确 function foo(){/* code */}(); //SyntaxError: Unexpected token ( // 但是如果你在括弧()里传入一个表达式,将不会有异常抛出 // 但是foo函数依然不会执行 function foo(){ /* code */ }( 1 ); // 因为它完全等价于下面这个代码,一个function声明后面,又声明了一个毫无关系的表达式: function foo(){ /* code */ } ( 1 ); // 由于括弧()和JS的&&,异或,逗号等操作符是在函数表达式和函数声明上消除歧义的 // 所以一旦解析器知道其中一个已经是表达式了,其它的也都默认为表达式了 // 不过,请注意下一章节的内容解释 var i = function () { return 10; } (); true && function () { /* code */ } (); 0, function () { /* code */ } (); // 如果你不在意返回值,或者不怕难以阅读 // 你甚至可以在function前面加一元操作符号 !function () { /* code */ } (); ~function () { /* code */ } (); -function () { /* code */ } (); +function () { /* code */ } (); // 还有一个情况,使用new关键字,也可以用,但我不确定它的效率 // http://twitter.com/kuvos/status/18209252090847232 new function () { /* code */ } new function () { /* code */ } () // 如果需要传递参数,只需要加上括弧()
作用域
IIFE可為局部變數提供一個封裝的作用域,並在IIFE回傳的函數中能夠存取此變數。這種方式即允許函數存取這個本地變數,即使這個函數在IIFE的詞法範圍之外執行時。
const uniqueId1 = function() { let count1 = 0; return function() { ++count1; return count1; }; }; uniqueId1(); //ƒ () {++count1;return count1;}
const uniqueId2 = function() { let count = 0; return count; }; uniqueId2(); //0 uniqueId2(); //0 uniqueId2(); //0
const uniqueId3 = (function() { let count3 = 0; return function() { ++count3; return count3; }; })(); uniqueId3(); //1 uniqueId3(); //2 uniqueId3(); //3 uniqueId3(); //4
const uniqueId4 = function() { let count4 = 0; return (function() { ++count4; return count4; })(); }; uniqueId4(); //1 uniqueId4(); //1 uniqueId4(); //1 uniqueId4(); //1
##注意:在IIFE之外無法存取這個計數變數count。除了從IIEF傳回的函數,別人無法讀寫該變數。這樣就能創造出真正的私有狀態,它只能以受控的方式進行修改。
當使用IIFE來傳回一個」封閉」一些本地變數來管理私有資料的函數時,let和##const
都不能取代它。
// 创建一个立即调用的匿名函数表达式 // return一个变量,其中这个变量里包含你要暴露的东西 // 返回的这个变量将赋值给counter,而不是外面声明的function自身 var counter = (function () { var i = 0; return { get: function () { return i; }, set: function (val) { i = val; }, increment: function () { return ++i; } }; } ()); // counter是一个带有多个属性的对象,上面的代码对于属性的体现其实是方法 counter.get(); // 0 counter.set(3); counter.increment(); // 4 counter.increment(); // 5 counter.i; // undefined 因为i不是返回对象的属性 i; // 引用错误: i 没有定义(因为i只存在于闭包)
閉包與IIFE
# 和一般function執行的時候傳參數一樣,自執行的函數表達式也可以這麼傳參,因為閉包直接可以引用傳入的這些參數,利用這些被lock住的傳入參數,自執行函數表達式可以有效地保存狀態。
// 这个代码是错误的,因为变量i从来就没背locked住 // 相反,当循环执行以后,我们在点击的时候i才获得数值 // 因为这个时候i操真正获得值 // 所以说无论点击那个连接,最终显示的都是I am link #10(如果有10个a元素的话) var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', function (e) { e.preventDefault(); alert('I am link #' + i); }, 'false'); } // 这个是可以用的,因为他在自执行函数表达式闭包内部 // i的值作为locked的索引存在,在循环执行结束以后,尽管最后i的值变成了a元素总数(例如10) // 但闭包内部的lockedInIndex值是没有改变,因为他已经执行完毕了 // 所以当点击连接的时候,结果是正确的 var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i++) { (function (lockedInIndex) { elems[i].addEventListener('click', function (e) { e.preventDefault(); alert('I am link #' + lockedInIndex); }, 'false'); })(i); } // 你也可以像下面这样应用,在处理函数那里使用自执行函数表达式 // 而不是在addEventListener外部 // 但是相对来说,上面的代码更具可读性 var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', (function (lockedInIndex) { return function (e) { e.preventDefault(); alert('I am link #' + lockedInIndex); }; })(i), 'false'); }
問題1、
for (var i = 0; i < 5; i++) { setTimeout(function(i) { console.log(i); }, i * 1000); }
問題2、
for (var i = 0; i < 5; i++) { setTimeout((function(i) { console.log(i); })(i), i * 1000); }
問題3、
for (var i = 0; i < 5; i++) { setTimeout((function(i) { return function() { console.log(i); } })(i), i * 1000); }
問題4、
for (var i = 0; i < 5; i++) { setTimeout((function(i) { console.log(i); }).bind(this,i), i * 1000); }
建議寫法:
var j = 0; for (i = 0; i < 5; i++) { setTimeout(function() { console.log(j); j++; }, i * 1000); }
之所以用到立即呼叫/執行的函數表達式,主要作用是 模仿區塊級作用域(也叫私有作用域):避免在全域作用域中加入過多的變數和函數。這樣每個開發人員既可以使用自己的變量,又不必擔心會影響或搞亂全域作用域。
IIFE打包壓縮
1、參數變短
IIFE可以進行參數變數名稱混疊,如下:
window.$ = function somethingElse() { // ... }; (function($) { // ... })(jQuery);
为了解决命名冲突问题,可以将一段代码封装在一个IIEF中,将一个全局变量(比如,jQuery)作为参数传入IIFE。在函数内部,就可以以一个任意的参数名(比如,$)来访问该参数值。
IIFE的这种特性可以用来优化代码,这种方式使代码能够被更有效的压缩。例如:
(function(window, document, undefined) { // ... })(window, document);
可以缩短函数的参数名为单个字母的标识符,更短标识符名会使文件的体积变得更小。
(function(w, d, u) { // ... })(window, document);
2、括号和分号的使用
我们知道,以下两种方法都是立即执行函数的写法:
// 下面2个括弧()都会立即执行 (function () { /* code */ } ()); (function () { /* code */ })();
注意这两种写法:匿名函数上面的写法都存在前后文;问题,所以需要注意的是匿名函数在压缩工具打包压缩后会出现上下文错误合并()的问题,例如第二种写法。如果下面的代码,未压缩之前是正常的,压缩后就不正常了,所以要严格上下文的;问题,而第一种就不会出现类似问题。
var a="bbb" (function(){ alert(1); })();
//var a = function(){} var a="bbb" (function(){ alert(1); }());
上述代码会报""bbb" is not a function"错误,若变量a是一函数,则会报"undefined is not a function",这是因为a变量或a函数会把他后面的匿名函数作为参数传入a中,这就很好的解释了为什么报前面提到的错误,这也很好地解释了为什么有人习惯在匿名函数之前添加;了,就是为了防止上文没有严格遵循javascript语法,漏掉;的问题。
相关推荐:
以上是JS之立即執行函數講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)