0

0

jquery源码的核心内容

不言

不言

发布时间:2018-07-09 15:16:56

|

1552人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了关于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 向jquery添加新的实例方法

  3. $.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也改变了,万一我们接下来还要使用该怎么办呢,所以我们还需要在做修改

MMM金融互助系统源码
MMM金融互助系统源码

MMM金融互助系统源码是以thinkphp为核心进行开发的3m金融互助平台。程序安装说明:1.恢复数据:将“数据备份”文件夹中的 urkeji.sql 文件请采用phpMyAdmin进行导入; 2.配置Sql数据库信息,文件路径:根目录下 config.php3.后台管理地址:http://域名/admin.php 用户名:100000 密码:admin1

下载
$.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对象,是一个包装容器。

3255929716-5b19096d66edf_articlex[1].png

你会看到在上面有一个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()

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

Hello,how are you?

$('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); //结果如下图

    4006296842-5b1a1f727ed30_articlex[1].png

    以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

    相关推荐:

    jquery源码的基本介绍

    热门AI工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    通义千问
    通义千问

    阿里巴巴推出的全能AI助手

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    相关专题

    更多
    go语言 注释编码
    go语言 注释编码

    本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

    2

    2026.01.31

    go语言 math包
    go语言 math包

    本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

    1

    2026.01.31

    go语言输入函数
    go语言输入函数

    本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

    1

    2026.01.31

    golang 循环遍历
    golang 循环遍历

    本专题整合了golang循环遍历相关教程,阅读专题下面的文章了解更多详细内容。

    0

    2026.01.31

    Golang人工智能合集
    Golang人工智能合集

    本专题整合了Golang人工智能相关内容,阅读专题下面的文章了解更多详细内容。

    1

    2026.01.31

    2026赚钱平台入口大全
    2026赚钱平台入口大全

    2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

    76

    2026.01.31

    高干文在线阅读网站大全
    高干文在线阅读网站大全

    汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

    73

    2026.01.31

    无需付费的漫画app大全
    无需付费的漫画app大全

    想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

    67

    2026.01.31

    漫画免费在线观看地址大全
    漫画免费在线观看地址大全

    想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

    19

    2026.01.31

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    jQuery 教程
    jQuery 教程

    共42课时 | 5.2万人学习

    HTML+CSS基础与实战
    HTML+CSS基础与实战

    共132课时 | 10万人学习

    tp6+adminlte搭建通用后台
    tp6+adminlte搭建通用后台

    共39课时 | 5.8万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号