首頁 >web前端 >js教程 >jQuery自呼叫匿名函數是如何呼叫的?

jQuery自呼叫匿名函數是如何呼叫的?

不言
不言原創
2018-08-01 16:04:163853瀏覽

這篇文章要跟大家介紹的內容是關於jQuery自呼叫匿名函數是如何呼叫的?有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

開啟jQuery原始碼,首先你會看到這樣的程式碼結構:

(function(window,undefined ){
})();

這是一個自呼叫匿名函數。什麼東東呢?在第一個括號內,建立一個匿名函數;第二個括號,立即執行

為什麼要創建這樣一個「自呼叫匿名函數」呢?
透過定義一個匿名函數,創建了一個「私有」的命名空間,該命名空間的變數和方法,不會破壞全域的命名空間。這點非常有用也是一個JS框架必須支援的功能,jQuery被應用在成千上萬的JavaScript程式中,必須確保jQuery創建的變數不能和導入他的程式所使用的變數發生衝突。
接下來看看在自呼叫匿名函數中都實作了什麼功能,依照程式碼順序排列:

(function( window, undefined ) {
// 构造jQuery对象
var jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context, rootjQuery );
}
// 工具函数 Utilities
// 异步队列 Deferred
// 浏览器测试 Support
// 数据缓存 Data
// 队列 queue
// 属性操作 Attribute
// 事件处理 Event
// 选择器 Sizzle
// DOM遍历
// DOM操作
// CSS操作
// 异步请求 Ajax
// 动画 FX
// 坐标和大小
window.jQuery = window.$ = jQuery;
})(window);

匿名函數從語法上叫函數直接量,JavaScript語法需要包圍匿名函數的括號,事實上自呼叫匿名函數有兩種寫法:

(function() {
console.info( this );
console.info( arguments );
}( window ) );
(function() {
console.info( this );
console.info( arguments );
})( window );

為什麼要傳入window呢?

透過傳入window變量,使得window由全域變數變成局部變量,當在jQuery程式碼區塊中存取window時,就不需要將作用域鏈回退到頂層作用域,這樣可以更快的存取window;這還不是關鍵所在,更重要的是,將window作為參數傳入,可以在壓縮程式碼時進行最佳化,看看jquery-1.6.1.min.js: (function(a,b){} )(window); // window 被優化為a  
透過以上的介紹,我們大概了解透過()可以使得一個函數表達式立即執行。

匿名函數作為一個“容器”,“容器”內部可以存取外部的變量,而外部環境不能存取“容器”內部的變量,
所以( function(){…} )()內部定義的變數不會和外部的變數發生衝突,俗稱「匿名包裹器」或「命名空間」。

(function () {
// ... 所有的变量和function都在这里声明,并且作用域也只能在这个匿名闭包里
// ...但是这里的代码依然可以访问外部全局的对象
}());

同下面
(function () {/ 內部程式碼/})();

通俗的講,()就是用來求值的,因此這個()任何時候都不能為空,因為它是要計算的。函數解析它只會解析到 {}為止,不會解析到 ()的。

   把表達式放在()中會回傳表達式的值;
   把函數放在()中會回傳函數本身;(function(){}());
   如果()緊接在函數後面,就是表示在呼叫函數,也就是對函數求值:(function(){})();

(function() {
//自执行函数中的内部变量,外部是无法访问的
var name = 'kevin';
})( window );

name  //undefined,無法取得name的值

程式碼在運作過程中,會優先解析【巳宣告的函數】;

          而函數表達式是當執行到它時,才會解析;
          匿名函數是不會單獨寫的,因此它的執行是需要其它函數的調用,通常看到的匿名函數,都是當作參數被傳遞的。而立即執行函數它本身就是個匿名函數,
          js程式執行的順序:
           //巳宣告的函數function test(){}
 //函數表達式var test = function(){}
           //立即執行函數 (function(){})();

立即執行函數配合閉包,在模組化中的應用,其中要明白幾個點:

1、要在函數體後面加括號就能立即調用,則這個函數必須是函數表達式,不能是函數聲明;

2、立即執行函數可以當作是私有作用域,作用域內部可以存取外部的變量,而外部環境是不能存取作用域內部的變數的,因此,立即執行函數是一個封閉的作用域,不會和外部作用域起衝突。
  JQuery使用的就是這種方法,將JQuery程式碼包裹在( function (window,undefined){…jquery程式碼…} (window)中,在全域作用域中呼叫JQuery程式碼時,可以達到保護JQuery內部變數的作用。
3、Module模式,是自執行函數的高階模式,可以非常方便的在各個匿名閉包中以全域物件呼叫閉包函數。                

Module 模式為:

  a.創建一個立即調用的匿名函數表達式
  b.return一個變量,其中這個變量裡包含你要暴露的東西
  c.返回的這個變量將賦值給window

(function () {
var i = 0;
return {
    get: function () {
        return i;
    },
    set: function (val) {
        i = val;
    },
    increment: function () {
        return ++i;
    }
};
} (window));
    // window作为一个带有多个属性的全局对象,上面的代码对于属性的体现其实是方法,它可以这样调用:
    window.get(); // 0
    window.set(3);
    window.increment(); // 4
    window.increment(); // 5

    window.i; // undefined 因为i不是返回对象的属性
    i; // 引用错误: i 没有定义(因为i只存在于闭包)
/

上面就是關於自呼叫匿名函數的解析,那麼這樣的函數它是怎麼被呼叫的呢?*//
以下是關於全域變數的調用,也就是匿名閉包函數的呼叫##*/再次搬離Module模式

Module 模式,也就是匿名閉包的建立與呼叫:

   a.创建一个立即调用的匿名函数表达式
   b.return一个变量,其中这个变量里包含你要暴露的东西
      c.返回的这个变量将赋值给window

window(或者是任意一个全局对象)作为一个带有多个属性的全局对象,也可以把window当成一个参数,以对象的方式,在其它函数中实现调用。用下面的例子说明:

(function ($, YAHOO) {
// 这里,我们的代码就可以使用全局的jQuery对象了,YAHOO也是一样
$.aa = function(){
    //code
}
} (jQuery, YAHOO));
//调用 jQuery.aa();

下面是一个标准的Module模式,通过匿名函数的返回值来返回这个全局变量:

var blogModule = (function () {
var my = {}, privateName = "博客园";

function privateAddTopic(data) {
    // 这里是内部处理代码
}

my.Name = privateName;
my.AddTopic = function (data) {
    privateAddTopic(data);
};

return my;
} ());
//调用 blogModule.my();

在一些大型项目里,将一个功能分离成多个文件是非常重要的,因为可以多人合作易于开发。再回头看看上面的全局参数导入例子,我们能否把blogModule自身传进去呢?答案是肯定的,我们先将blogModule传进去,添加一个函数属性,然后再返回就达到了我们所说的目的:

var blogModule = (function (my) {
my.AddPhoto = function () {
    //添加内部代码  
};
return my;
} (blogModule || {}));


(function (my){
my.AddPhoto = function () {
    //添加内部代码  
};
return my;
})(blogModule || {}));
//调用 blogModule.AddPhoto();

那么,多个自执行函数间是怎么调用的呢?

(function(owner) {
//第一个匿名闭包
owner.debug = true;
//Ajax相关参数配置
owner.ajax = {
    timeout: 10000,
    type: 'post',
    dataType: 'json',
};
})(window.C = {}));

如果第二个函数想调用 全局变量为C中的 对象呢?要怎么写?

(function($, owner) {
//这里调用上面全局变量为C 中的对象呢
if(!C.debug) return false;
var url = 'aaa.html';
mui.ajax({
    url: url,
    dataType: C.ajax.dataType,
    type: C.ajax.type,
});
})(mui, window.app = {});

再举个例子,同样的,不同自执行闭包函数间的调用方法:

(function($, owner) {
//获取语言闭包
owner.getLanguage = function() {
    var language = localStorage.getItem(C.state.field.language);
    if(typeof language == "undefined" || language === null || language == '') {
        var currentLang = navigator.language;
        if(!currentLang)
            currentLang = navigator.browserLanguage;
        language = currentLang.toLowerCase();
        language = language.replace(/-/g, '_');

        if(language != 'en_us' && language != 'zh_cn')
            language = 'en_us';

        localStorage.setItem(C.state.field.language, language);
    }

    //在上面的解析中有说过,Module模式,return 一个变量,这个变量就是要爆露的东西。通过这个函数的全局变量,这个  language  可以在任何地方调用   
    //return一个变量,其中这个变量里包含你要暴露的东西 
    //全局调用  storage.language                                  
    return language;
};
})(mui, window.storage = {}));
(function($, owner) {
owner.language = {};
owner.preload = function(settings){
    var defaults = {
        name: 'i18n',
        language: '',
        path: '/',
        cache: true,
        encoding: 'UTF-8',
        autoReplace: true,
        success: null,
        error: null,
    };
    
    settings = $.extend(defaults, settings);
    if(settings.language === null || settings.language == '') {
        //全局调用  storage.language                                                                            
        settings.language = storage.getLanguage();
    }
}   
})(mui, window.i18n = {});

所以 匿名闭包的调用规则是这样的,立即执行(最后一个括号) (window),如果把window作为一个参数进行传递,那么就把它以对象的方式,在其它函数中实现全局调用。

相关推荐:

js实现模态窗口增加与删除案例分享(纯代码)

js对象类型怎么判断?详解js里的基本类型转换

以上是jQuery自呼叫匿名函數是如何呼叫的?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn