最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2014年05月27日 11:10:10   作者:  
這篇文章主要介紹了jQuery 2.0.3 源碼分析之core(一)整體架構(gòu),需要的朋友可以參考下

拜讀一個(gè)開(kāi)源框架,最想學(xué)到的就是設(shè)計(jì)的思想和實(shí)現(xiàn)的技巧。

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

不過(guò)這幾年都是做移動(dòng)端,一直御用zepto, 最近抽出點(diǎn)時(shí)間把jquery又給掃一遍

我也不會(huì)照本宣科的翻譯源碼,結(jié)合自己的實(shí)際經(jīng)驗(yàn)一起拜讀吧!

github上最新是jquery-master,加入了AMD規(guī)范了,我就以官方最新2.0.3為準(zhǔn)

整體架構(gòu)

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

例如:

復(fù)制代碼 代碼如下:

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

從上面的寫法上至少可以發(fā)現(xiàn)2個(gè)問(wèn)題

1. jQuery對(duì)象的構(gòu)建方式

2 .jQuery方法的調(diào)用方式

分析一:jQuery的無(wú)new構(gòu)建

JavaScript是函數(shù)式語(yǔ)言,函數(shù)可以實(shí)現(xiàn)類,類就是面向?qū)ο缶幊讨凶罨镜母拍?/P>

復(fù)制代碼 代碼如下:

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

var a = new aQuery();

a.name();

這是常規(guī)的使用方法,顯而易見(jiàn)jQuery不是這樣玩的

jQuery沒(méi)有使用new運(yùn)行符將jQuery顯示的實(shí)例化,還是直接調(diào)用其函數(shù)

按照jQuery的書寫方式

復(fù)制代碼 代碼如下:

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

要實(shí)現(xiàn)這樣,那么jQuery就要看成一個(gè)類,那么$()應(yīng)該是返回類的實(shí)例才對(duì)

所以把代碼改一下:

復(fù)制代碼 代碼如下:

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

通過(guò)new aQuery(),雖然返回的是一個(gè)實(shí)例,但是也能看出很明顯的問(wèn)題,死循環(huán)了!

那么如何返回一個(gè)正確的實(shí)例?

在javascript中實(shí)例this只跟原型有關(guān)系

那么可以把jQuery類當(dāng)作一個(gè)工廠方法來(lái)創(chuàng)建實(shí)例,把這個(gè)方法放到j(luò)Query.prototye原型中

復(fù)制代碼 代碼如下:

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

當(dāng)執(zhí)行aQuery() 返回的實(shí)例:

 

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

問(wèn)題來(lái)了init的this指向的是aQuery類,如果把init函數(shù)也當(dāng)作一個(gè)構(gòu)造器,那么內(nèi)部的this要如何處理?

復(fù)制代碼 代碼如下:

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

這樣的情況下就出錯(cuò)了,因?yàn)閠his只是指向aQuery類的,所以需要設(shè)計(jì)出獨(dú)立的作用域才行

jQuery框架分隔作用域的處理

復(fù)制代碼 代碼如下:

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

很明顯通過(guò)實(shí)例init函數(shù),每次都構(gòu)建新的init實(shí)例對(duì)象,來(lái)分隔this,避免交互混淆

那么既然都不是同一個(gè)對(duì)象那么肯定又出現(xiàn)一個(gè)新的問(wèn)題

例如:

復(fù)制代碼 代碼如下:

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())

拋出錯(cuò)誤,無(wú)法找到這個(gè)方法,所以很明顯new的init跟jquery類的this分離了

怎么訪問(wèn)jQuery類原型上的屬性與方法?

     做到既能隔離作用域還能使用jQuery原型對(duì)象的作用域呢,還能在返回實(shí)例中訪問(wèn)jQuery的原型對(duì)象?

實(shí)現(xiàn)的關(guān)鍵點(diǎn)

復(fù)制代碼 代碼如下:

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

通過(guò)原型傳遞解決問(wèn)題,把jQuery的原型傳遞給jQuery.prototype.init.prototype

換句話說(shuō)jQuery的原型對(duì)象覆蓋了init構(gòu)造器的原型對(duì)象

因?yàn)槭且脗鬟f所以不需要擔(dān)心這個(gè)循環(huán)引用的性能問(wèn)題

復(fù)制代碼 代碼如下:

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

百度借網(wǎng)友的一張圖,方便直接理解:

fn解釋下,其實(shí)這個(gè)fn沒(méi)有什么特殊意思,只是jQuery.prototype的引用

 

分析二:鏈?zhǔn)秸{(diào)用

DOM鏈?zhǔn)秸{(diào)用的處理:

1.節(jié)約JS代碼.

2.所返回的都是同一個(gè)對(duì)象,可以提高代碼的效率

通過(guò)簡(jiǎn)單擴(kuò)展原型方法并通過(guò)return this的形式來(lái)實(shí)現(xiàn)跨瀏覽器的鏈?zhǔn)秸{(diào)用。

利用JS下的簡(jiǎn)單工廠模式,來(lái)將所有對(duì)于同一個(gè)DOM對(duì)象的操作指定同一個(gè)實(shí)例。

這個(gè)原理就超簡(jiǎn)單了

復(fù)制代碼 代碼如下:

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

把代碼分解一下,很明顯實(shí)現(xiàn)鏈?zhǔn)降幕緱l件就是實(shí)例this的存在,并且是同一個(gè)

復(fù)制代碼 代碼如下:

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

所以我們?cè)谛枰準(zhǔn)降姆椒ㄔL問(wèn)this就可以了,因?yàn)榉祷禺?dāng)前實(shí)例的this,從而又可以訪問(wèn)自己的原型了

復(fù)制代碼 代碼如下:

aQuery.init().name()

優(yōu)點(diǎn):節(jié)省代碼量,提高代碼的效率,代碼看起來(lái)更優(yōu)雅

最糟糕的是所有對(duì)象的方法返回的都是對(duì)象本身,也就是說(shuō)沒(méi)有返回值,這不一定在任何環(huán)境下都適合。

Javascript是無(wú)阻塞語(yǔ)言,所以他不是沒(méi)阻塞,而是不能阻塞,所以他需要通過(guò)事件來(lái)驅(qū)動(dòng),異步來(lái)完成一些本需要阻塞進(jìn)程的操作,這樣處理只是同步鏈?zhǔn)剑惒芥準(zhǔn)絡(luò)query從1.5開(kāi)始就引入了Promise,jQuery.Deferred后期在討論。

分析三:插件接口

jQuery的主體框架就是這樣,但是根據(jù)一般設(shè)計(jì)者的習(xí)慣,如果要為jQuery或者jQuery prototype添加屬性方法,同樣如果要提供給開(kāi)發(fā)者對(duì)方法的擴(kuò)展,從封裝的角度講是不是應(yīng)該提供一個(gè)接口才對(duì),字面就能看懂是對(duì)函數(shù)擴(kuò)展,而不是看上去直接修改prototype.友好的用戶接口,

jQuery支持自己擴(kuò)展屬性,這個(gè)對(duì)外提供了一個(gè)接口,jQuery.fn.extend()來(lái)對(duì)對(duì)象增加方法

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

復(fù)制代碼 代碼如下:

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

jQuery.extend 對(duì)jQuery本身的屬性和方法進(jìn)行了擴(kuò)展

jQuery.fn.extend 對(duì)jQuery.fn的屬性和方法進(jìn)行了擴(kuò)展

通過(guò)extend()函數(shù)可以方便快速的擴(kuò)展功能,不會(huì)破壞jQuery的原型結(jié)構(gòu)

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

針對(duì)fn與jQuery其實(shí)是2個(gè)不同的對(duì)象,在之前有講述:

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

extend的實(shí)現(xiàn)

復(fù)制代碼 代碼如下:

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

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一個(gè)參數(shù)為true,即 jQuery.extend( true, obj1, obj2 ); 的情況
        deep = target;  // 此時(shí)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時(shí),this指的是jQuery;jQuery.fn.extend時(shí),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
                // 如果是深拷貝,且被拷貝的屬性值本身是個(gè)對(duì)象
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷貝的屬性值是個(gè)數(shù)組
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷貝的屬性值是個(gè)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;

總結(jié):

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

相關(guān)文章

  • 移動(dòng)端 一個(gè)簡(jiǎn)單易懂的彈出框

    移動(dòng)端 一個(gè)簡(jiǎn)單易懂的彈出框

    本文給大家分享一段簡(jiǎn)單的jquery代碼實(shí)現(xiàn)一個(gè)簡(jiǎn)單易懂的彈出框,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧
    2016-07-07
  • jQuery實(shí)現(xiàn)平滑滾動(dòng)的標(biāo)簽分欄切換效果

    jQuery實(shí)現(xiàn)平滑滾動(dòng)的標(biāo)簽分欄切換效果

    這篇文章主要介紹了jQuery實(shí)現(xiàn)平滑滾動(dòng)的標(biāo)簽分欄切換效果,涉及jquery鼠標(biāo)事件及頁(yè)面元素樣式的動(dòng)態(tài)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • 修改Jquery Dialog 位置的實(shí)現(xiàn)方法

    修改Jquery Dialog 位置的實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇修改Jquery Dialog 位置的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • jQuery中的deferred使用方法

    jQuery中的deferred使用方法

    deferred對(duì)象是jQuery的回調(diào)函數(shù)解決方案,jQuery之前的版本中異步回調(diào)這塊做的不是很好,所以后期補(bǔ)上了該解決方案。接下來(lái)通過(guò)本文給大家介紹jQuery中的derferred使用方法,非常不錯(cuò),需要的朋友參考下
    2017-03-03
  • 淺析Cookie中的Path與domain

    淺析Cookie中的Path與domain

    本篇文章主要是對(duì)Cookie中的Path與domain進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-12-12
  • jQuery插件zepto.js簡(jiǎn)單實(shí)現(xiàn)tab切換

    jQuery插件zepto.js簡(jiǎn)單實(shí)現(xiàn)tab切換

    這篇文章主要介紹了jQuery插件zepto.js簡(jiǎn)單實(shí)現(xiàn)tab切換的代碼,十分的簡(jiǎn)潔,有需要的小伙伴可以參考下
    2015-06-06
  • jQuery中prependTo()方法用法實(shí)例

    jQuery中prependTo()方法用法實(shí)例

    這篇文章主要介紹了jQuery中prependTo()方法用法,實(shí)例分析了prependTo()方法的功能、定義及匹配的元素插入指定元素之前的使用技巧,需要的朋友可以參考下
    2015-01-01
  • 解析prototype,JQuery中跳出each循環(huán)的方法

    解析prototype,JQuery中跳出each循環(huán)的方法

    這篇文章主要介紹了在prototype,JQuery中跳出each循環(huán)的方法。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-12-12
  • Jquery Ajax方法傳值到action的方法

    Jquery Ajax方法傳值到action的方法

    這篇文章主要介紹了Jquery Ajax方法傳值到action的方法,需要的朋友可以參考下
    2014-05-05
  • EasyUI布局 高度自適應(yīng)

    EasyUI布局 高度自適應(yīng)

    這篇文章主要介紹EasyUI高度自適應(yīng)的問(wèn)題,比較實(shí)用,需要的朋友可以參考下。
    2016-06-06

最新評(píng)論

商城县| 临桂县| 兰考县| 清水县| 临夏县| 湖州市| 贵港市| 鞍山市| 贺州市| 武鸣县| 水富县| 仲巴县| 宁城县| 弥勒县| 鱼台县| 应城市| 临安市| 惠水县| 广东省| 宝丰县| 津南区| 夹江县| 永平县| 西充县| 五华县| 方城县| 达州市| 沈阳市| 怀柔区| 水富县| 彭水| 彭阳县| 泽普县| 溆浦县| 澳门| 县级市| 德阳市| 芜湖县| 综艺| 临澧县| 绥宁县|