1. 程式人生 > >jQuery分析(2) - $工廠函數分析

jQuery分析(2) - $工廠函數分析

bject 所有 合並 ams cto cnblogs rip 詳細 blog

jQuery分析(2) - $工廠函數分析

前言

從這節進入jQuery的世界,首先從jQuery的入口函數開始了解jQuery()或$是如何運作的,這裏我給出了一個最小的例子來分析。

回憶

在進入分析代碼前我們回想下jQuery的使用方法有哪些呢?

  • selector,[context]
    • selector:用來查找的字符串
    • context:作為待查找的 DOM 元素集、文檔或 jQuery 對象。
  • element
    • 一個用於封裝成jQuery對象的DOM元素
  • object
    • 一個用於封裝成jQuery對象
  • elementArray
    • 一個用於封裝成jQuery對象的DOM元素數組。
  • jQuery object
    • 一個用於克隆的jQuery對象。
  • jQuery()
    • 返回一個空的jQuery對象。

大家知道$函數等於jQuery函數,在調用完$函數後它會選擇出傳遞第一個參數對應的元素或創建一個新元素,如果給定了第二個參數(context)那就是從context這個上下文向下查找。實現原理並不難,復雜的是涉及的邏輯相對多和兼容性問題。接下來是我整理的一個jQuery最小框架,我們一起來看看jQuery如何實現$(‘div‘).width()神奇的方法。

jQuery庫本質的實現原理(對象模擬數組)源碼 官方完整源碼地址 / 簡化版源碼地址

(function() {
    var jQuery = function(selector) {
        return new jQuery.fn.init(selector);
    };
    jQuery.fn = jQuery.prototype = {
        selector: "",
        length: 0,
        constructor: jQuery,
        find: function(selector) {
            var ret = [];
            ret.push(document.getElementById(selector));
            ret = this.pushStack(ret);
            ret.selector = selector;
            return ret;
        },
        pushStack: function(elems) {
            var ret = this.constructor();
            for(var i = 0, il = elems.length; i < il; i++) {
                ret[i] = elems[i];
            }
            ret.length = i;
            ret.prevObject = this;
            ret.context = this.context;
            return ret;
        },
        msg: function() {
            console.log(‘test function‘);
        }
    };

    var init = jQuery.fn.init = function(selector) {
        if(!selector) {
            return this;
        }
        if(typeof selector == ‘string‘) {
            return rootjQuery.find(selector);
            //return document.getElementById(selector);
        } else if(selector.nodeType) {
            this.context = this[0] = selector;
            this.length = 1;
            return this;
        }
    };
    init.prototype = jQuery.fn;
    var rootjQuery = jQuery(document);
    window.$ = jQuery;
})();

上面的代碼是我在拋開了jQuery的其他邏輯後整理出來它的架構的基礎,接著一步一步來仔細看看他是如何運行的。

jQuery框架核心步驟

  • 對於一個jQuery對象的調用分2種:
    • 新選擇一個元素或者創建一個元素(在jQuery函數中new一個jQuery.fn.init構造函數)
    • 執行一個jQuery對象方法(執行jQuery在原型鏈上的方法)
  • 對傳入的selector進行不同操作解析(不傳入任何參數將返回一個空的jQuery對象實例)
  • 對於傳入一個選擇器參數進行find查找元素,對於傳入字符串參數進行DOM解析創建元素
  • 創建一個新的jQuery對象,將以上選擇好的元素或者創建好的DOM節點用數組的方式合並到新的jQuery對象中並返回

$(‘div‘) 方法調用順序圖

技術分享

框架代碼關鍵點

  • jQuery.fn = jQuery.prototype
  • jQuery.fn.init
  • pushStack

jQuery.fn = jQuery.prototype 這個對象是jQuery對象的原型鏈當使用 $(‘div‘) 創建出來的jQuery對象便擁有改對象的所有方法

jQuery.fn.init 函數對傳入的參數selector進行不同類型的解析,如果selector是一個字符串則找到他的id的元素。

jQuery.fn.init = function(selector) {
    if (!selector) {
        return this;
    }
    if (typeof selector == ‘string‘) {
        // 是字符串則找到這個字符串id的元素
        return rootjQuery.find(selector);
    } else if (selector.nodeType) {
        // 如果是dom元素直接賦值和修正length,最後返回this
        this.context = this[0] = selector;
        this.length = 1;
        return this;
    }
};

pushStack首先創建一個空的jQuery對象,然後把查找到的元素合並到空對象中並進行length修正,最後修改prevObject以便最上次操作的元素進行跟蹤(詳細請見end()函數)

pushStack: function(elems) {
    // 創建一個空的jQuery對象
    var ret = this.constructor();
    // 把找到的元素放入ret空對象中
    for (var i = 0, il = elems.length; i < il; i++) {
        ret[i] = elems[i];
    }
    // 修正length
    ret.length = i;
    // 跟蹤上次更改元素操作
    ret.prevObject = this;
    // 修正上下文
    ret.context = this.context;
    // 返回裝好元素的jQuery對象
    return ret;
}

調用jQuery.prototype原型鏈上的msg函數示例

var elem = $(‘div‘);
elem.msg();    // test function

總結

分析jQuery或$函數執行流程,用簡化版例子分析jQuery從入口函數到返回jQuery對象過程中都做了什麽事情並且對 $(‘div‘).msg() 調用方法進行了分析。通過這個簡化版例子了解jQuery的基礎架構。這對於以後的學習是必要。

如有疏忽、遺漏、錯誤請狠狠批評謝謝。

轉載:http://www.cnblogs.com/monsterooo/p/5479642.html

jQuery分析(2) - $工廠函數分析