jQuery 的源码看过吗?能不能简单概况一下它的实现原理?

🌙
手机阅读
本文目录结构

jQuery 的源码看过吗?能不能简单概况一下它的实现原理?

1、闭包机制;

 // 以下截取自 jquery 源码片段
 (function( window, undefined ) {
    /*    源码内容    */
 })( window );

上面这一小段代码来自于 1.9.0 当中 jquery 的源码,它是一个无污染的 JS 插件的标准写法,专业名词叫闭包。可以把它简单的看做是一个函数,与普通函数不同的是,这个函数没有名字,而且会立即执行

我们将里面的变量变成了局域变量,这不仅可以提高运行速度,更重要的是我们在引用 jquery 的 JS 文件时,不会因为 jquery 当中的变量太多,而与其它的 JS 框架的变量命名产生冲突;闭包中的变量声明没有污染到外面的全局变量;;

2、作为全局的一个属性;

window.jQuery = window.$ = jQuery;

这一句话将我们在闭包当中定义的 jQuery 对象导出为全局变量 jQuery 和 $,因此我们才可以在外部直接使用 jQuery 和 $。

window 是默认的 JS 上下文环境,因此将对象绑定到 window 上面,就相当于变成了传统意义上的全局变量,

3、最核心的功能,就是选择器;

首先我们进入 jquery 源码中,可以很容易的找到 jquery 对象的声明,看过以后会发现,原来我们的 jquery 对象就是 init 对象。

jQuery = function( selector, context ) {
	return new jQuery.fn.init( selector, context, rootjQuery );
}

这里出现了 jQuery.fn 这样一个东西,它的由来可以在 jquery 的源码中找到,它其实代表的就是 jQuery 对象的原型。

jQuery.fn = jQuery.prototype;
jQuery.fn.init.prototype = jQuery.fn;

这两句话,第一句把 jQuery 对象的原型赋给了 fn 属性,第二句把 jQuery 对象的原型又赋给了 init 对象的原型。也就是说,init 对象和 jQuery 具有相同的原型,因此我们在上面返回的 init 对象,就与 jQuery 对象有一样的属性和方法。

我们不打算深究 init 这个方法的逻辑以及实现,但是我们需要知道的是,jQuery 其实就是将 DOM 对象加了一层包裹,而寻找某个或者若干个 DOM 对象是由 sizzle 选择器负责的,

jQuery 对象有很多的属性和方法;对于属性来说,我们最需要关注的只有一个属性,就是 [0] 属性,[0] 其实就是原生的 DOM 对象。

很多时候,我们在 jQuery 和 DOM 对象之间切换时需要用到 [0] 这个属性。

从截图也可以看出,jQuery 对象其实主要就是把原生的 DOM 对象存在了 [0] 的位置,并给它加了一系列简便的方法。

这个索引 0 的属性我们可以从一小段代码简单的看一下它的由来,下面是 init 方法中的一小段对 DOMElement 对象作为选择器的源码。

// Handle $(DOMElement)
if ( selector.nodeType ) {
	/*     可以看到,这里将 DOM 对象赋给了 jQuery 对象的 [0] 这个位置  */
	this.context = this[0] = selector;
	this.length = 1;
	return this;
}

这一小段代码可以在 jquery 源码中找到,它是处理传入的选择参数是一个 DOM 对象的情况。

可以看到,里面很明显的将 jQuery 对象索引 0 的位置以及 context 属性,都赋予了 DOM 对象

。代码不仅说明了这一点,也同时说明了,我们使用 $(DOMElement) 可以将一个 DOM 对象转换为 jQuery 对象,从而通过转换获得 jQuery 对象的简便方法。

4、ready 方法

$(function(){}) 或者是 ready 方法;

实现类似 jquery 的 ready 方法的效果我们是可以简单做到的,它的实现原理就是,维护一个函数数组,然后不停的判断 DOM 是否加载完毕,倘若加载完毕就触发所有数组中的函数。

遵循着这一思想,LZ 拿出很久之前写的一个小例子,来给各位看一下。

(function( window, undefined ) {
var jQuery = {
        isReady:false,// 文档加载是否完成的标识
        readyList:[],// 函数序列
        //onload 事件实现
        ready : function(fn){
                // 如果是函数,加入到函数序列
                if(fn && typeof fn == 'function' ){
                    jQuery.readyList.push(fn);
                }
                // 文档加载完成,执行函数序列。
                if(jQuery.isReady){
                    for(var i = 0;i < jQuery.readyList.length ;i++){
                        fn = jQuery.readyList[i];
                        jQuery.callback(fn);
                    }
                    return jQuery;
                }
            },
        // 回调
        callback : function(fn){
            fn.call(document,jQuery);
        }
    };
    // 导出对象
    window.$ = window.jQuery = jQuery;
    // 判断加载是否完成
    var top = false;
    try {
        top = window.frameElement == null && document.documentElement;
    } catch(e) {}
    if ( top && top.doScroll ) {
        (function doScrollCheck() {
            try {
                top.doScroll("left");
                jQuery.isReady = true;
                jQuery.ready();
            } catch(e) {
                setTimeout( doScrollCheck, 50 );
            }
        })();
    }
}(window));

这段代码是 LZ 从之前的例子摘出来的,它的实现逻辑非常简单,但是可以达到 jQuery 的 ready 方法的效果,

5、extend 方法

简单说两个 extend 方法的常用方式。

  • 1、使用 jQuery.fn.extend 可以扩展 jQuery 对象,使用 jQuery.extend 可以扩展 jQuery,前者类似于给类添加普通方法,后者类似于给类添加静态方法。
  • 2、两个 extend 方法如果有两个 object 类型的参数,则会将后面的参数对象属性扩展到第一个参数对象上面,扩展时可以再添加一个 boolean 参数控制是否深度拷贝。

更多面试题

如果你想了解更多的前端面试题,请点击下面进行选择,这里基本包涵了市场上的所有前端方面的面试题,让你面试更加顺利。

这些题库还在更新中,如果你有不错的面试题库欢迎分享给我,我整理后放上来;人人为我,我为人人,互帮互助,共同提高,祝大家都拿到心仪的Offer!

AXIHE / 精选资源

浏览全部教程

面试题

学习网站

前端培训
自己甄别

前端书籍

关于朱安邦

我叫 朱安邦,阿西河的站长,在杭州。

以前是一名平面设计师,后来开始接接触前端开发,主要研究前端技术中的JS方向。

业余时间我喜欢分享和交流自己的技术,欢迎大家关注我的 Bilibili

关注我: Github / 知乎

于2021年离开前端领域,目前重心放在研究区块链上面了

我叫朱安邦,阿西河的站长

目前在杭州从事区块链周边的开发工作,机械专业,以前从事平面设计工作。

2014年底脱产在老家自学6个月的前端技术,自学期间几乎从未出过家门,最终找到了满意的前端工作。更多>

于2021年离开前端领域,目前从事区块链方面工作了