搜尋
首頁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
    jquery实现多少秒后隐藏图片jquery实现多少秒后隐藏图片Apr 20, 2022 pm 05:33 PM

    实现方法:1、用“$("img").delay(毫秒数).fadeOut()”语句,delay()设置延迟秒数;2、用“setTimeout(function(){ $("img").hide(); },毫秒值);”语句,通过定时器来延迟。

    axios与jquery的区别是什么axios与jquery的区别是什么Apr 20, 2022 pm 06:18 PM

    区别:1、axios是一个异步请求框架,用于封装底层的XMLHttpRequest,而jquery是一个JavaScript库,只是顺便封装了dom操作;2、axios是基于承诺对象的,可以用承诺对象中的方法,而jquery不基于承诺对象。

    jquery怎么修改min-height样式jquery怎么修改min-height样式Apr 20, 2022 pm 12:19 PM

    修改方法:1、用css()设置新样式,语法“$(元素).css("min-height","新值")”;2、用attr(),通过设置style属性来添加新样式,语法“$(元素).attr("style","min-height:新值")”。

    jquery怎么在body中增加元素jquery怎么在body中增加元素Apr 22, 2022 am 11:13 AM

    增加元素的方法:1、用append(),语法“$("body").append(新元素)”,可向body内部的末尾处增加元素;2、用prepend(),语法“$("body").prepend(新元素)”,可向body内部的开始处增加元素。

    jquery中apply()方法怎么用jquery中apply()方法怎么用Apr 24, 2022 pm 05:35 PM

    在jquery中,apply()方法用于改变this指向,使用另一个对象替换当前对象,是应用某一对象的一个方法,语法为“apply(thisobj,[argarray])”;参数argarray表示的是以数组的形式进行传递。

    jquery怎么删除div内所有子元素jquery怎么删除div内所有子元素Apr 21, 2022 pm 07:08 PM

    删除方法:1、用empty(),语法“$("div").empty();”,可删除所有子节点和内容;2、用children()和remove(),语法“$("div").children().remove();”,只删除子元素,不删除内容。

    jquery怎么去掉只读属性jquery怎么去掉只读属性Apr 20, 2022 pm 07:55 PM

    去掉方法:1、用“$(selector).removeAttr("readonly")”语句删除readonly属性;2、用“$(selector).attr("readonly",false)”将readonly属性的值设置为false。

    jquery on()有几个参数jquery on()有几个参数Apr 21, 2022 am 11:29 AM

    on()方法有4个参数:1、第一个参数不可省略,规定要从被选元素添加的一个或多个事件或命名空间;2、第二个参数可省略,规定元素的事件处理程序;3、第三个参数可省略,规定传递到函数的额外数据;4、第四个参数可省略,规定当事件发生时运行的函数。

    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脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    3 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    3 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.如果您聽不到任何人,如何修復音頻
    3 週前By尊渡假赌尊渡假赌尊渡假赌

    熱工具

    SublimeText3 Mac版

    SublimeText3 Mac版

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

    SAP NetWeaver Server Adapter for Eclipse

    SAP NetWeaver Server Adapter for Eclipse

    將Eclipse與SAP NetWeaver應用伺服器整合。

    MinGW - Minimalist GNU for Windows

    MinGW - Minimalist GNU for Windows

    這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    WebStorm Mac版

    WebStorm Mac版

    好用的JavaScript開發工具