像如下的程式碼所示,就是一個匿名立即執行函數:
(function(window, undefined){ // 代码... })(window);
2.1 包住 function(){}
的括號的意義
這個括號的目的,是為了把function(){}
#轉換成表達式。像一些函式庫的源碼,喜歡用如下方式代替:
~function(){ // 代码... }();
或這樣:
+function(){ // 代码... }();
其實,作用都一樣,都是把function(){}
轉換成一個可執行的表達式,方便執行。
如果去掉該括號,則會報錯。因為單純的function(){}
不是可執行的表達式,會直接報錯。如下圖:
# 2.1 第二個括號的意義
理解了第一個括號的意義,第二個括號就很簡單了,就是執行表達式了。
以這段程式碼為例子,講解參數
var wall = {}; (function(window, WALL, undefined){ })(window, wall);
參數分為形參和實參。
function(window, WALL, undefined)
三個參數為形參,第二個括號(window, wall)
的兩個參數為實參。
也即可以理解為 window == window
,wall == WALL
。
2.1 普通形參考
普通形參是指由window
和wall
這樣的實際變數傳入指定,可以為任何類型的變數。一個形參就對應一個實參
2.2 特殊形參就對應一個實參
2.2 特殊形參undefined 為什麼形參要多寫一個undefined,這是一個很有趣的話題。
undefined會預設賦值為undefined。
undefined的作用如下:
if(wall == undefined){ // 代码... }
四、寫法解析
4.1 普通寫法
var wall = {}; // 声明定义一个命名空间wall // 定义方法 (function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); }; })(window, wall); (function(window, WALL, undefined){ // 给wall命名空间绑定方法 whoIam WALL.whoIam = function(){ console.log('wall'); }; })(window, wall); // 调用 wall.say(); wall.whoIam();
先定義一個命名空間,然後再為這個命名空間加東西。這是最普遍的寫法,也是最好理解的。 不足的地方就是必須先宣告一個命名空間,然後才能執行相關的綁定程式碼。存在順序載入的問題。
wall變數進行重複var聲明,所以這段程式碼是可以執行的。 我可以把IIFE函數拆分成多個檔案來加載,而不會出現普通寫法需要注意的問題。
需要注意的點:
1.IIFE的頭部,都要先進行檢查命名空間是否已經實例化,如果還沒實例化,則進行實例化。
wall命名空間內容。
4.3 寬放大模式
(function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } })(window, window.wall || (window.wall = {})); (function(window, WALL, undefined){ // 给wall命名空间绑定方法 whoIam WALL.whoIam = function(){ console.log('wall'); } })(window, window.wall || (window.wall = {})); // 调用 wall.say(); wall.whoIam();
寬放大模式的重點注意的地方:運算子
進行取巧。 如果
window.wall是已經實例化的,非not defined。則直接傳回
window.wallWALL
。不會執行||運算子後面的內容。 window.wall
尚未實例化,則進行實例化。這裡要注意的點是實例化是一個賦值運算,需要用括號包起來,變成表達式去執行,才不會報錯。 表達式(window.wall = {})執行完畢後,會傳回新
物件###window.wall###的參考。 ### 宽放大模式的好处:是可以切割成多个文件进行加载,而不必考虑文件加载的先后顺序,不存在强耦合关系。
当然,如果IIFE里面的方法互相引用,还是存在加载依赖的问题。这个问题可以用加载器Require.js等工具解决,这里就不讨论了。
;(function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } })(window, window.wall || (window.wall = {}));
眼尖的已经看出区别了,就是文件开始的地方,先写上分号;
。
这样,多个文件合并的时候,才不会出现收尾相接,代码出现错乱的问题。比如下面这种情况:
// a.js 文件 wall.log() // b.js 文件 (function(window, WALL, undefined){ // 给wall命名空间绑定方法say WALL.say = function(){ console.log('hello'); } })(window, window.wall || (window.wall = {}));
由于a.js文件的wall.log()
少写了分号,跟b.js文件合并后,js就会认为‘wall.log()(...)’是需要这么执行的,结果代码就报错了。
觉得不错的,可以关注<a href="http://www.php.cn/js/js-weixinapp-module.html" target="_blank">模块化</a>
这个系列的文章,容我后续码字,敬请期待!
以上是javascript模組化程式設計詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!