亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

jQuery 2.0.3 源碼分析之core(一)整體架構

2019-11-20 15:07:08
字體:
來源:轉載
供稿:網友

拜讀一個開源框架,最想學到的就是設計的思想和實現的技巧。

廢話不多說,jquery這么多年了分析都寫爛了,老早以前就拜讀過,

不過這幾年都是做移動端,一直御用zepto, 最近抽出點時間把jquery又給掃一遍

我也不會照本宣科的翻譯源碼,結合自己的實際經驗一起拜讀吧!

github上最新是jquery-master,加入了AMD規范了,我就以官方最新2.0.3為準

整體架構

jQuery框架的核心就是從HTML文檔中匹配元素并對其執行操作、

例如:

復制代碼 代碼如下:

$().find().css()
$().hide().html('....').hide().

從上面的寫法上至少可以發現2個問題

1. jQuery對象的構建方式

2 .jQuery方法的調用方式

分析一:jQuery的無new構建

JavaScript是函數式語言,函數可以實現類,類就是面向對象編程中最基本的概念

復制代碼 代碼如下:

var aQuery = function(selector, context) {
        //構造函數
}
aQuery.prototype = {
    //原型
    name:function(){},
    age:function(){}
}

var a = new aQuery();

a.name();

這是常規的使用方法,顯而易見jQuery不是這樣玩的

jQuery沒有使用new運行符將jQuery顯示的實例化,還是直接調用其函數

按照jQuery的書寫方式

復制代碼 代碼如下:

$().ready()
$().noConflict()

要實現這樣,那么jQuery就要看成一個類,那么$()應該是返回類的實例才對

所以把代碼改一下:

復制代碼 代碼如下:

var aQuery = function(selector, context) {
       return new aQuery();
}
aQuery.prototype = {
    name:function(){},
    age:function(){}
}

通過new aQuery(),雖然返回的是一個實例,但是也能看出很明顯的問題,死循環了!

那么如何返回一個正確的實例?

在javascript中實例this只跟原型有關系

那么可以把jQuery類當作一個工廠方法來創建實例,把這個方法放到jQuery.prototye原型中

復制代碼 代碼如下:

var aQuery = function(selector, context) {
       return  aQuery.prototype.init();
}
aQuery.prototype = {
    init:function(){
        return this;
    }
    name:function(){},
    age:function(){}
}

當執行aQuery() 返回的實例:

 

很明顯aQuery()返回的是aQuery類的實例,那么在init中的this其實也是指向的aQuery類的實例

問題來了init的this指向的是aQuery類,如果把init函數也當作一個構造器,那么內部的this要如何處理?

復制代碼 代碼如下:

var aQuery = function(selector, context) {
       return  aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        this.age = 18
        return this;
    },
    name: function() {},
    age: 20
}

aQuery().age  //18

這樣的情況下就出錯了,因為this只是指向aQuery類的,所以需要設計出獨立的作用域才行

jQuery框架分隔作用域的處理

復制代碼 代碼如下:

jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context, rootjQuery );
    },

很明顯通過實例init函數,每次都構建新的init實例對象,來分隔this,避免交互混淆

那么既然都不是同一個對象那么肯定又出現一個新的問題

例如:

復制代碼 代碼如下:

var aQuery = function(selector, context) {
       return  new aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        this.age = 18
        return this;
    },
    name: function() {},
    age: 20
}

//Uncaught TypeError: Object [object Object] has no method 'name'
console.log(aQuery().name())

拋出錯誤,無法找到這個方法,所以很明顯new的init跟jquery類的this分離了

怎么訪問jQuery類原型上的屬性與方法?

     做到既能隔離作用域還能使用jQuery原型對象的作用域呢,還能在返回實例中訪問jQuery的原型對象?

實現的關鍵點

復制代碼 代碼如下:

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

通過原型傳遞解決問題,把jQuery的原型傳遞給jQuery.prototype.init.prototype

換句話說jQuery的原型對象覆蓋了init構造器的原型對象

因為是引用傳遞所以不需要擔心這個循環引用的性能問題

復制代碼 代碼如下:

var aQuery = function(selector, context) {
       return  new aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this.age
    },
    age: 20
}
aQuery.prototype.init.prototype = aQuery.prototype;
console.log(aQuery().name()) //20

百度借網友的一張圖,方便直接理解:

fn解釋下,其實這個fn沒有什么特殊意思,只是jQuery.prototype的引用

 

分析二:鏈式調用

DOM鏈式調用的處理:

1.節約JS代碼.

2.所返回的都是同一個對象,可以提高代碼的效率

通過簡單擴展原型方法并通過return this的形式來實現跨瀏覽器的鏈式調用。

利用JS下的簡單工廠模式,來將所有對于同一個DOM對象的操作指定同一個實例。

這個原理就超簡單了

復制代碼 代碼如下:

aQuery().init().name()
分解
a = aQuery();
a.init()
a.name()

把代碼分解一下,很明顯實現鏈式的基本條件就是實例this的存在,并且是同一個

復制代碼 代碼如下:

aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this
    }
}

所以我們在需要鏈式的方法訪問this就可以了,因為返回當前實例的this,從而又可以訪問自己的原型了

復制代碼 代碼如下:

aQuery.init().name()

優點:節省代碼量,提高代碼的效率,代碼看起來更優雅

最糟糕的是所有對象的方法返回的都是對象本身,也就是說沒有返回值,這不一定在任何環境下都適合。

Javascript是無阻塞語言,所以他不是沒阻塞,而是不能阻塞,所以他需要通過事件來驅動,異步來完成一些本需要阻塞進程的操作,這樣處理只是同步鏈式,異步鏈式jquery從1.5開始就引入了Promise,jQuery.Deferred后期在討論。

分析三:插件接口

jQuery的主體框架就是這樣,但是根據一般設計者的習慣,如果要為jQuery或者jQuery prototype添加屬性方法,同樣如果要提供給開發者對方法的擴展,從封裝的角度講是不是應該提供一個接口才對,字面就能看懂是對函數擴展,而不是看上去直接修改prototype.友好的用戶接口,

jQuery支持自己擴展屬性,這個對外提供了一個接口,jQuery.fn.extend()來對對象增加方法

從jQuery的源碼中可以看到,jQuery.extend和jQuery.fn.extend其實是同指向同一方法的不同引用

復制代碼 代碼如下:

jQuery.extend = jQuery.fn.extend = function() {

jQuery.extend 對jQuery本身的屬性和方法進行了擴展

jQuery.fn.extend 對jQuery.fn的屬性和方法進行了擴展

通過extend()函數可以方便快速的擴展功能,不會破壞jQuery的原型結構

jQuery.extend = jQuery.fn.extend = function(){...}; 這個是連等,也就是2個指向同一個函數,怎么會實現不同的功能呢?這就是this 力量了!

針對fn與jQuery其實是2個不同的對象,在之前有講述:

    jQuery.extend 調用的時候,this是指向jQuery對象的(jQuery是函數,也是對象!),所以這里擴展在jQuery上。
    而jQuery.fn.extend 調用的時候,this指向fn對象,jQuery.fn 和jQuery.prototype指向同一對象,擴展fn就是擴展jQuery.prototype原型對象。
    這里增加的是原型方法,也就是對象方法了。所以jQuery的api中提供了以上2中擴展函數。

extend的實現

復制代碼 代碼如下:

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},    // 常見用法 jQuery.extend( obj1, obj2 ),此時,target為arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一個參數為true,即 jQuery.extend( true, obj1, obj2 ); 的情況
        deep = target;  // 此時target是true
        target = arguments[1] || {};    // target改為 obj1
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  // 處理奇怪的情況,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   // 處理這種情況 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  // jQuery.extend時,this指的是jQuery;jQuery.fn.extend時,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options則為 obj2、obj3...
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {    // 防止自引用,不贅述
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 如果是深拷貝,且被拷貝的屬性值本身是個對象
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷貝的屬性值是個數組
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷貝的屬性值是個plainObject,比如{ nick: 'casper' }
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

                    // Never move original objects, clone them
                    target[ name ] = jQuery.extend( deep, clone, copy );  // 遞歸~

                // Don't bring in undefined values
                } else if ( copy !== undefined ) {  // 淺拷貝,且屬性值不為undefined
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;

總結:

    通過new jQuery.fn.init() 構建一個新的對象,擁有init構造器的prototype原型對象的方法
    通過改變prorotype指針的指向,讓這個新的對象也指向了jQuery類的原型prototype
    所以這樣構建出來的對象就繼續了jQuery.fn原型定義的所有方法了

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美激情精品久久久久久变态| 欧美性猛交xxxx| 亚洲第一页在线| 亚洲欧美国内爽妇网| 色天天综合狠狠色| 欧美最猛性xxxx| 精品国内产的精品视频在线观看| 欧美特黄级在线| 欧美成人中文字幕| 国产成人精品亚洲精品| 亚洲一级黄色av| 亚洲黄色av网站| 国产精品久久久久久av| 欧美激情精品久久久| 久久久久久国产三级电影| 夜夜嗨av色一区二区不卡| 1769国产精品| 亚洲视频一区二区三区| 久久久精品在线观看| 久久99久久99精品中文字幕| 久久精品在线播放| 国产精品久久久av久久久| 91在线观看免费网站| 欧美激情精品久久久久久免费印度| 成人福利视频网| www.亚洲天堂| 欧美精品一区在线播放| 最新69国产成人精品视频免费| 国产欧美在线视频| 亚洲视频一区二区三区| 国产日韩欧美黄色| 国产精品久久久久久久9999| 国产精品视频在线观看| 成人免费自拍视频| 国产91精品高潮白浆喷水| 欧美性受xxxx白人性爽| 成人乱人伦精品视频在线观看| 欧美综合一区第一页| 高清欧美电影在线| 91精品国产综合久久香蕉的用户体验| 久久久久久999| 91久久国产婷婷一区二区| 国产精品福利网站| 亚洲精品永久免费| 精品中文字幕乱| 欧美日韩电影在线观看| 久久久久久国产精品| 国产精品视频网| 91久久精品国产91久久性色| 久久九九有精品国产23| 26uuu亚洲国产精品| 国产精品青青在线观看爽香蕉| 91亚洲精品一区二区| 久久91精品国产91久久久| 国产精品入口免费视| 日韩在线视频导航| 色综合久久悠悠| 国产91色在线|免| 成人激情春色网| 国模精品一区二区三区色天香| 欧美极品xxxx| 亚洲影视中文字幕| 国产不卡av在线| 亚洲最大激情中文字幕| 亚洲激情国产精品| 欧美激情亚洲另类| 欧洲一区二区视频| 亚洲男人av电影| 久久久久国色av免费观看性色| 欧美巨乳在线观看| 国产一区二区日韩精品欧美精品| 国产欧美精品日韩| 日韩精品视频在线免费观看| 国产精品69av| 在线成人激情黄色| 日韩大陆欧美高清视频区| 亚洲a在线观看| 亚洲国产成人精品女人久久久| 日韩精品视频观看| 日本国产高清不卡| 92看片淫黄大片看国产片| 亚洲国产精品国自产拍av秋霞| 91精品久久久久久久| 国产精品99久久99久久久二8| 久久69精品久久久久久国产越南| 久久综合色影院| 精品久久久久久中文字幕大豆网| 国产成人精品久久久| 中文字幕亚洲在线| 久久精品国产亚洲一区二区| 久久韩国免费视频| 国产精品h在线观看| 精品成人av一区| 正在播放欧美视频| 亚洲加勒比久久88色综合| 国产精品免费视频久久久| 国产精品18久久久久久首页狼| 亚洲精品美女视频| 国产精品日韩欧美大师| 国产一区二区视频在线观看| 欧美性xxxxxx| 日本国产一区二区三区| 97在线视频精品| 欧美午夜无遮挡| 国内偷自视频区视频综合| 91久久精品久久国产性色也91| 欧美成人激情在线| 国产精品中文字幕在线观看| 欧美精品在线免费播放| 欧美精品videos性欧美| 成人啪啪免费看| 精品成人av一区| 亚洲r级在线观看| 久久久久成人精品| 亚洲国产精品高清久久久| 久久久久久国产精品| 成人激情黄色网| 国产一区私人高清影院| 国产成人在线亚洲欧美| 欧美成人在线免费视频| 久久精品小视频| 奇门遁甲1982国语版免费观看高清| 性色av一区二区三区免费| 日本亚洲精品在线观看| 国语自产精品视频在线看一大j8| 91香蕉国产在线观看| 日韩欧美成人网| 国产日韩欧美中文在线播放| 国产日韩欧美另类| 欧美日韩一区二区在线| 国产成人高清激情视频在线观看| 国产亚洲精品久久久久久777| 91中文在线视频| 亚洲国产欧美一区二区丝袜黑人| 97精品在线观看| 欧美精品久久一区二区| 日韩男女性生活视频| 国产精品jizz在线观看麻豆| 69久久夜色精品国产7777| 午夜精品99久久免费| 欧美精品免费看| 国产精品久久久久久亚洲调教| 欧美电影免费观看电视剧大全| 日韩欧美在线视频观看| 久久精品电影网| 久久韩剧网电视剧| 国产日韩欧美日韩| 日韩精品极品视频| 孩xxxx性bbbb欧美| 国产精品日韩在线播放| 色偷偷噜噜噜亚洲男人的天堂| 欧亚精品在线观看| 欧美天天综合色影久久精品| 亚洲精品自在久久| 欧美激情一区二区三区久久久| 精品国产精品三级精品av网址| 亚洲xxxx18| 国产欧美韩国高清| 国产精品99久久久久久久久久久久| 国产精品国模在线| 国产精品99久久久久久人| 欧美最顶级的aⅴ艳星| 日韩精品在线免费播放| 亚洲最大福利网|