搜尋
首頁web前端js教程jquery源碼的核心內容

jquery源碼的核心內容

Jul 09, 2018 pm 03:16 PM
jquery

這篇文章主要介紹了關於jquery原始碼學習之jQuery的核心內容,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

核心模組

一、物件的建構
// 方法一
function ajquery (name) {
    this.name = name;
    this.sayName = function() {
        return this.name;
    }
    return this;
}

// 方法二
function ajquery(name) {
    this.name = name;
}

ajquery.prototype = {
    sayName : function () {
        return this.name;
    }
}

上面是兩種創建類別的方式,雖然最後實現的效果是一致的但是在效能上確實不一致的,當我們實例化三個ajquery物件的時候,對於方法一,每個實例都有一個sayName方法,這樣就浪費了內存,增加了開銷,方法二則是吧sayName放到了原型鏈上了,這樣每一個實例對像都能共享這個方法了(是一個不錯的選擇呢),只是透過scope連接到原型鏈上查找,這樣就無形之中也就是多了一層作用域鏈的查找;

jquery的物件在性能上考慮,所以就必須採用原型鏈了呢

jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context );
}
jQuery.fn = jQuery.prototype = {
    init:function(){
        return this
    },
    jquery: version,
    constructor: jQuery,
    // ………………
}

var a = $() ;
二、 jquery中的物件的建構器的分離

new一個實例的過程

1. 创建一个空对象
2. 将构造函数的作用域赋给这个对象,这个this就指向了这个对象了
3. 执行构造函数中的代码
4. 返回这个对象

new主要是吧原型鍊跟實例的this連接起來

  • 我們常用的類別式寫法如下:

var $$ = ajquery = function (selector) {
    this.selector = selector;
    return this;
}
ajquery.fn = ajquery.prototype = {
    getSelector: function () {
        return this.selector;
    },
    constructor: ajquery
}

var a = new $$('aaa');
a.getSelector();
  • 如果不適用new同樣也可以實作

var $$ = ajquery = function (selector) {
    if(!(this instanceof ajquery)) {
        return new ajquery(selector);
    }
    this.selector = selector;
    return this;
}
  • jquery中的寫法

var $$ = ajquery = function(selector) {
    return new ajquery.fn.init(selector);
}

ajquery.fn = ajquery.prototype = {
    name: 'meils',
    init: function (selector){
        console.log(this);
    },
    constructor: ajquery
}

init是ajQuery原型上作為建構器的一個方法,那麼其this就不是ajQuery了,所以this就完全引用不到ajQuery的原型了,所以這裡透過new把init方法與ajQuery給分離成2個獨立的構造器。

三、 方法的鍊式呼叫
$('input[type="button"]')
    .eq(0).click(function() {
        alert('点击我!');
}).end().eq(1)
.click(function() {
    $('input[type="button"]:eq(0)').trigger('click');
}).end().eq(2)
.toggle(function() {
    $('.aa').hide('slow');
}, function() {
    $('.aa').show('slow');
});
// end()方法是将最近的筛选操作还原为前一步操作的状态

看這個程式碼的結構,我們或多或少都能猜到其意義:

☑  找出type類型為button的input元素

☑  找到第一個按鈕,並綁定click事件處理函數

☑  回傳所有按鈕,再找到第二個

☑  為第二個按鈕綁定click事件處理函數

☑  為第三個按鈕綁定toggle事件處理函數

jquery的核心概念是寫的少,辦的多。

jquery.fn.init = function() {
    return this;
}

jquery.fn.get = function() {
    return this;
}

// 透過返回this來實現鍊式操作,因為傳回目前實例的this,從而又可以存取自己的原型了,這樣的就節省程式碼量,提高程式碼的效率,程式碼看起來更優雅。但是這種方法有一個問題是:所有物件的方法回傳的都是物件本身,也就是說沒有回傳值,所以這種方法不一定在任何環境下都適合。

雖然Javascript是無阻塞語言,但是他並不是沒阻塞,而是不能阻塞,所以他需要透過事件來驅動,異步來完成一些本需要阻塞進程的操作,這樣處理只是同步鍊式,除了同步鍊式還有非同步鍊式,非同步鍊式jQuery從1.5開始就引進了Promise,jQuery.Deferred後期再討論。

四、插件介面的設計

jQUery為插件的編寫提供了兩個介面,一種時$.extend()將其作為靜態方法處理,另一種時將方法掛在到 $.fn上,作為jquery的原型物件的方法。

fn與jQuery其實是2個不同的對象,在之前有講解:jQuery.extend 呼叫的時候,this是指向jQuery對象的(jQuery是函數,也是對象!),所以這裡擴展在jQuery上。而jQuery.fn.extend 呼叫的時候,this指向fn對象,jQuery.fn 和jQuery.prototype指向同一對象,擴展fn就是擴展jQuery.prototype原型對象。這裡增加的是原型方法,也就是物件方法了。所以jQuery的API中提供了以上2個擴充函數。

五、外掛程式開發

jquery外掛的開發模式一共有三種。

  1. $.extend() 來擴充jquery靜態方法

  2. #$.fn 新增新的實例方法

$.widget()應用jquery ui的部件工廠方式

第一種方式只是在$的命名空間下創建了一個靜態方法,可以直接使用$來呼叫執行即可。而不需要使用$('selector')來選取DOM物件再來呼叫方法。

第三種方法是用來寫更進階的外掛程式使用的,一般不使用。 第二種方法是我們平時開發所,最常用的一種形式,稍後我們將仔細學習該方法$.extend()

$.extend({
    sayName: function(name) {
        console.log(name);
    }
})

$.sayName('meils');
// 直接使用 $.sayName 来调用

// 通过$.extend()向jQuery添加了一个sayHello函数,然后通过$直接调用。到此你可以认为我们已经完成了一个简单的jQuery插件了。
這種方法用來定義一些輔助方法,還是有用的。
$.extend({
    log: function(message) {
        var now = new Date(),
            y = now.getFullYear(),
            m = now.getMonth() + 1, //!JavaScript中月分是从0开始的
            d = now.getDate(),
            h = now.getHours(),
            min = now.getMinutes(),
            s = now.getSeconds(),
            time = y + '/' + m + '/' + d + ' ' + h + ':' + min + ':' + s;
        console.log(time + ' My App: ' + message);
    }
})
$.log('initializing...'); //调用
$.fn 開發外掛

一、基本使用

$.fn.setColor = function() {
    this.css('color', 'red');
}

//这里的this指向调用我们这个方法的那个对象

二、each()遍歷

#我們也可以對我們所獲得的元素的集合的每一個元素使用我們的方法。 ###
$.fn.addUrl = function() {
    this.css('css', 'red');
    this.each(function() {
        $(this).append('i');
    })
}
######jquery選擇器###選取的是一個集合,因此可以###$.each()###來遍歷每一個元素,在###each###內部,###this###`指的就是每一個DOM元素了,如果需要呼叫jquery的方法,那麼就需要在用###$####來包裝一下了;####### #三、鍊式呼叫######
$.fn.setSelector = function() {
    this.css('color', 'red');
    return this.each(function() {

    })
}
######四、參數的接收#######

我们会使用$.extend()来处理我们参数,因为这个方法如果传入多个参数后,他会把这些合并到第一个上。如果存在有同名参数,那么遵循后面的覆盖前面的。

// 利用这一点,我们可以在插件里定义一个保存插件参数默认值的对象,同时将接收来的参数对象合并到默认对象上,最后就实现了用户指定了值的参数使用指定的值,未指定的参数使用插件默认值。

$.fn.setStyle = function(options) {
    var default = {
        color: 'red',
        fontSize: '15px'
    }
    var setting = $.extend(default, optioins);

    return this.css({
        'color': setting.color,
        'fontSize': setting.fontSize
    })
}

上面的参数处理有一点不足,我们把default也改变了,万一我们接下来还要使用该怎么办呢,所以我们还需要在做修改

$.fn.setStyle = function(options) {
    var default = {
        color: 'red',
        fontSize: '15px'
    }
    var setting = $.extend({}, default, optioins);

    return this.css({
        'color': setting.color,
        'fontSize': setting.fontSize
    })
}

五、面向对象开发插件

你可能需要一个方法的时候就去定义一个function,当需要另外一个方法的时候,再去随便定义一个function,同样,需要一个变量的时候,毫无规则地定义一些散落在代码各处的变量。

还是老问题,不方便维护,也不够清晰。当然,这些问题在代码规模较小时是体现不出来的。

// 如果将需要的重要变量定义到对象的属性上,函数变成对象的方法,当我们需要的时候通过对象来获取,一来方便管理,二来不会影响外部命名空间,因为所有这些变量名还有方法名都是在对象内部。

var beautify = function(ele, option) {
    this.$element = this.ele;
    this.default = {
        'color': 'red',
        'fontSize': '12px',
        'textDecoration':'none'
    }
    this.ops = $.extend({}, default, option);
}

beautify.prototype = {
    setStyle : function() {
        return this.$element.css({
            'color': this.options.color,
            'fontSize': this.options.fontSize,
            'textDecoration': this.options.textDecoration
        })

        // return this对象,实现链式调用

    }
}


$.fn.myPlugin = function(option) {
    var beautify = new beautify(this, option);

    beautify.setStyle();
}



/// 使用

$('a').myPlugin({
    'color': '#2C9929',
    'fontSize': '20px'
});

六、解决命名冲突

因为随着你代码的增多,如果有意无意在全局范围内定义一些变量的话,最后很难维护,也容易跟别人写的代码有冲突。
比如你在代码中向全局window对象添加了一个变量status用于存放状态,同时页面中引用了另一个别人写的库,也向全局添加了这样一个同名变量,最后的结果肯定不是你想要的。所以不到万不得已,一般我们不会将变量定义成全局的。

一个最好的方法就是始终使用自调用的匿名函数来包裹你的代码,这样,就可以完全放心的使用自己的变量了。
绝对不会有命名冲突。

;(function() {
    var beautify = function(ele, option) {
    this.$element = this.ele;
    this.default = {
        'color': 'red',
        'fontSize': '12px',
        'textDecoration':'none'
    }
    this.ops = $.extend({}, default, option);
}

beautify.prototype = {
    setStyle : function() {
        return this.$element.css({
            'color': this.options.color,
            'fontSize': this.options.fontSize,
            'textDecoration': this.options.textDecoration
        })

        // return this对象,实现链式调用

    }
}


$.fn.myPlugin = function(option) {
    var beautify = new beautify(this, option);

    beautify.setStyle();
}
})();
  • 优化一

var foo=function(){
    //别人的代码
}//注意这里没有用分号结尾

//开始我们的代码。。。
(function(){
    //我们的代码。。
    alert('Hello!');
})();

由于前面的代码没有加;号 , 然后我们的插件加载出错了,所以我们在我们插件的最开始加一个;号来强制前面的结束。

  • 优化二

我们可以将一些系统变量传入我们的插件,这样可以缩短变量的作用域链,将其作为我们插件内部的局部变量来使用,这样可以大大提高我们的速度和性能。

;(function($, window, document, undefined) {
    var beautify = function(ele, option) {
    this.$element = this.ele;
    this.default = {
        'color': 'red',
        'fontSize': '12px',
        'textDecoration':'none'
    }
    this.ops = $.extend({}, default, option);
}

beautify.prototype = {
    setStyle : function() {
        return this.$element.css({
            'color': this.options.color,
            'fontSize': this.options.fontSize,
            'textDecoration': this.options.textDecoration
        })

        // return this对象,实现链式调用

    }
}


$.fn.myPlugin = function(option) {
    var beautify = new beautify(this, option);

    beautify.setStyle();
}
})(jQuery, window,document,);

一个安全,结构良好,组织有序的插件编写完成。


六、版本回溯

jquery能过够方便的获取到DOM元素,并且能够遍历它们。你知道这些背后的原理吗?

通过对sizzle的分析,我们知道jquery获取到的是一个jquery对象,是一个包装容器。

jquery源碼的核心內容

你会看到在上面有一个prevObject对象。

在jquery内部维护着一个jquery对象栈,遍历方法每一次遍历都会找到一个新的元素,每一个元素都是一个jquery对象,然后jquery会把这些元素都放到这个栈中。(入栈)

$('ul').find('li');


// 这句话可以拆分,第一个jquery对象是$('ul'); 第二个jquery对象是$('ul').find('li');


// 首先将$('ul')入栈
// 然后将li集合(类数组对象)入栈

因为栈中的每一个元素都是一个jquery对象,每一个jquery对象都有着三个属性,分别时contextselectorprevObject, prevObject 属性就是指向对象栈中的前一个元素的。

这个prevObject 就比较有意思了。它指向前一个元素。

举例子了:


        parent     
  • child
var aaron = $("#aaron");     aaron.find('li').click(function(){         alert(1);     //1     }) // 如果我们想在返回父级 aaron.find('li').click(function(){     alert(1);     //1 }).end().click(function() {     alert(2); }) // end()方法就是进行了回溯,

jquery为我们操纵对象栈提供了两个有用的方法

  • end()

  • addSelf()

这两个方法都是进行版本的回退。

  • end()

返回最近的一次筛选的上一个状态。回到最近的一个"破坏性"操作之前。即,将匹配的元素列表变为前一次的状态。

<p><span>Hello</span>,how are you?</p>

$('p').find('span').end();
// 选取所有的p元素,查找并选取span子元素,然后再回过来选取p元素

end()方法返回的就是一个prevObject;

  • addBank


       
  • list item 1
  •    
  • list item 2
  •    
  • list item 3
  •    
  • list item 4
  •    
  • list item 5
$('li.third-item').nextAll().addBank()                 .css(); // 初始选择位于第3项,初始化堆栈集合只包含这项。调用.nextAll() 后将第4和第5项推入堆栈。最后,调用.addBack() 合并这两个组元素在一起,创建一个jQuery对象,指向所有三个项元素(按照文档中的顺序):{[,
  • ,
  •  ]} // [1] li.third-item 入栈 // [2] 4、5入栈 // [3] addBank 合并重组
    .addBack()方法导致前一组遍历堆栈中的DOM元素被添加到当前组。

    来举例子喽

    // First Example
    $("p.before-addback").find("p").addClass("background");
    // p元素添加背景
    
    // Second Example
    $("p.after-addback").find("p").addBack().addClass("background");
    // 选中的p元素以及前一个元素合并到栈中,全部添加背景
    利用这个DOM元素栈可以减少重复的查询和遍历的操作,而减少重复操作也正是优化jQuery代码性能的关键所在。

    在对对象栈的操作中,用到了一个pushStack()

    pushStack 生成了一个新 jQuery 对象 ret,ret 的 prevObject 属性是指向调用 pushStack 函数的那个 jQuery 对象的,这样就形成了一个栈链,其它原型方法如 find、nextAll、filter 等都可以调用 pushStack 函数,返回一个新的 jQuery 对象并维持对象栈。
    jQuery.fn.pushStack = function (elems) {
    
      // 将 elems 合并到 jQuery 对象中
      var ret = jQuery.merge(this.constructor(), elems);
    
      // 实现对象栈
      ret.prevObject = this;
    
      // 返回
      return ret;
    }
    • end()源码解析

    jQuery.fn.end = function() {
      return this.prevObject || this.constructor; // 如果存在之前的jquery对象就返回它,如果不存在上一个,就返回当前的jQuery对象。
    }
    • addBank() 源码解析

    jQuery.fn.addBank = function(selector) {
      return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector));
    
      // 如果参数为空,就把当前的jquery对象的上一个jQuery对象一起合并为一个新的对象。如果指定了参数,那么就在上一个对象中查找这个对象。
    
    }
    
    
        
    • 1
    •   
    • 2
    •   
    • 3
    •   
    • 4
    var li = $('ul').find('li'); console.log(li); //结果如下图

    jquery源碼的核心內容

    以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP中文網!

    相關推薦:

    jquery原始碼的基本介紹

    ################################################################################################################################# ####
  • 以上是jquery源碼的核心內容的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
    JavaScript,C和瀏覽器之間的關係JavaScript,C和瀏覽器之間的關係May 01, 2025 am 12:06 AM

    引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

    node.js流帶打字稿node.js流帶打字稿Apr 30, 2025 am 08:22 AM

    Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE

    Python vs. JavaScript:性能和效率注意事項Python vs. JavaScript:性能和效率注意事項Apr 30, 2025 am 12:08 AM

    Python和JavaScript在性能和效率方面的差異主要體現在:1)Python作為解釋型語言,運行速度較慢,但開發效率高,適合快速原型開發;2)JavaScript在瀏覽器中受限於單線程,但在Node.js中可利用多線程和異步I/O提升性能,兩者在實際項目中各有優勢。

    JavaScript的起源:探索其實施語言JavaScript的起源:探索其實施語言Apr 29, 2025 am 12:51 AM

    JavaScript起源於1995年,由布蘭登·艾克創造,實現語言為C語言。 1.C語言為JavaScript提供了高性能和系統級編程能力。 2.JavaScript的內存管理和性能優化依賴於C語言。 3.C語言的跨平台特性幫助JavaScript在不同操作系統上高效運行。

    幕後:什麼語言能力JavaScript?幕後:什麼語言能力JavaScript?Apr 28, 2025 am 12:01 AM

    JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

    Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

    Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

    Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

    Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

    JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

    是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    Atom編輯器mac版下載

    Atom編輯器mac版下載

    最受歡迎的的開源編輯器

    VSCode Windows 64位元 下載

    VSCode Windows 64位元 下載

    微軟推出的免費、功能強大的一款IDE編輯器