jQuery 学习笔记:jQuery 代码结构

这是我学习 jQuery 过程中整理的笔记,这一部分主要包括 jQuery 的代码最外层的结构,写出来整理自己的学习成果,有错误欢迎指出。

jQuery 的最外层 $,jQuery

(function (global, factory) {
    "use strict";
    if (typeof module === "object" && typeof module.exports === "object") { // 判断是否使用 commonjs 环境
        module.exports = global.document ?
            factory(global, true) :
            function (w) {
                if (!w.document) {
                    throw new Error("jQuery requires a window with a document");
                }
                return factory(w);
            };
    } else {
        factory(global);
    }
})(typeof window !== "undefined" ? window : this,  function (window, noGlobal){
    if (typeof define === "function" && define.amd) {  // 是否使用 AMD 模块化规范
        define("jquery", [], function () {
            return jQuery;
        });
    }
    var
        _jQuery = window.jQuery,
        _$ = window.$;
    jQuery.noConflict = function (deep) {
        if (window.$ === jQuery) {
            window.$ = _$;
        }
        if (deep && window.jQuery === jQuery) {
            window.jQuery = _jQuery;
        }
        return jQuery;
    };
    if (!noGlobal) {
        window.jQuery = window.$ = jQuery;
    }
    return jQuery;
});

上面是 jQuery-3.3.1 的一部分代码,是最外层的一部分,包含了大量的信息。

(function (global, factory) {
})(typeof window !== "undefined" ? window : this, function (window, noGlobal){
});

jQuery 代码包含在一个自执行的函数内,然后返回出一个指向 jQuery 的索引,就形成了一个闭包,利用 jQuery 对象,可以访问定义在自执行函数内的方法,在外面则访问不到,防止变量命名同外界产生冲突,同时,window 对象作为参数传入函数,在函数内,将 jQuery 和 windowwindow. 挂 载 到 w i n d o w 对 象 对 象 上 , 这 样 , 在 外 界 也 可 以 直 接 通 过 w i n d o w . 和 window.jQuery 访问到 jQuery 对象。通常使用较多的 window. , 实 际 指 的 就 是 w i n d o w . ,但通常会省略掉 window 对象。

    if (!noGlobal) {
        window.jQuery = window.$ = jQuery; // 将 jQuery 和 $ 挂载到 window 对象对象上
    }
    return jQuery; // 然后返回出一个指向 jQuery 的索引

同时,为了防止不同库对 jQuery 的 指 向 产 生 冲 突 , j Q u e r y 还 可 以 将 和 jQuery 还原成原来的指向,只要使用 jQuery.noConflict 方法。

    var
        _jQuery = window.jQuery, // 保存 window.jQuery 的值
        _$ = window.$; // 保存 window.$ 的值
    jQuery.noConflict = function (deep) {
        if (window.$ === jQuery) {
            window.$ = _$;
        }
        if (deep && window.jQuery === jQuery) { // 根据参数判断是否还原 window.jQuery 的值
            window.jQuery = _jQuery;
        }
        return jQuery;
    };

先使用 jQuery 和 window.jQuerywindow. 保 存 w i n d o w . j Q u e r y 和 w i n d o w . 的原始值,如果调用 jQuery.noConflict 方法,判断传入的参数,如果参数值为 false,就仅释放 $,还原为原来的值,如果参数值为 true,就将 window.jQuery 也还原为原来的值。

jQuery 函数的重载

jQuery 在使用时,既可以作为一个函数,直接调用 , 传 入 参 数 , 也 可 以 将 其 作 为 对 象 , 调 用 对 象 的 方 法 , 作 为 对 象 的 情 况 之 后 再 讨 论 , 先 说 将 作为函数使用。

由于 jQuery 中同名函数会覆盖,传入参数不同时,不能从多个同名函数中选择某个函数,而且根据函数名选择唯一的函数,所以当传入参数种类不同时,就需要根据参数的个数,类型等信息判断具体的处理方式了。当调用 jQuery 时,指向的是一个函数。

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

会直接返回一个以 jQuery.fn.init 为构造函数,new 出的对象。而在 jQuery.fn.init 函数中,则会根据传入的参数的不同,进行不同的处理。

init = jQuery.fn.init = function (selector, context, root) {
        var match, elem;
        if (!selector) { // 如果第一个参数为空,直接 return 调用函数的对象
          return this;
        }
        root = root || rootjQuery;
        if (typeof selector === "string") {
            // 参数为字符串,进行处理
        } else if (selector.nodeType) {
            // 参数为元素节点,进行处理
        } else if (isFunction(selector)) {
            //参数为函数,进行处理
        }
        return jQuery.makeArray(selector, this);
      };
    init.prototype = jQuery.fn; // 将 init 函数的原型指定为 jQuery.fn,则 init 构造函数 new 出的对象就都可以直接使用 init 函数的原型也就是 jQuery.fn 包含的方法。

当参数为空时,返回 init 函数的调用者,最终,会返回 jQuery,即 $ 对象,可以使用对象上的方法。当第一个参数为字符串时,可以是选择器,html代码(会创建DOM元素并包装成 jQuery 对象),当为 DOM 对象时,包装成 jQuery 对象,当为函数时,$(fn) 相当于 $(document).ready(fn),会在页面页面 DOM 加载完成后调用 fn,性能上优于 window.onload。

jQuery 插件

上面说到,jQuery 可以作为一个对象,使用其绑定的方法,例如 .trimjQueryinitjQuery.fnDOMjQueryjQuery.fn . t r i m 方 法 , 可 以 去 除 字 符 串 两 边 的 空 格 。 此 外 , j Q u e r y 对 象 的 构 造 函 数 i n i t 的 原 型 指 向 j Q u e r y . f n , 则 D O M 对 象 被 包 装 成 j Q u e r y 对 象 后 , 就 可 以 调 用 j Q u e r y . f n 的 方 法 了 , 例 如 (‘p’).css 方法等。这两种方法都可以添加新的方法,对应了 jQuery 的两种插件。

添加插件使用的是 jQuery.extend 函数,以及 jQuery.fn.extend,其实指向的是同一个函数,只是函数的调用者不同,this 指向就不同了。

$.extend 函数本身可以作为一个工具函数,处理对象的合并,语法 jQuery.extend([deep], target, object1, [objectN]),这个函数会判断第一个参数是否是一个 Boolean 值(可选),如果是,则进行深拷贝,如果不是,则进行浅拷贝。然后根据除了 Boolean 值之外的其他参数的个数,判断是否是添加插件,如果剩余参数不止一个,则第一个作为 target,其他对象的属性将会复制到 target 上,而如果只有一个参数,则会将这个参数对象的方法添加到 jQuery 对象上,或者 jQuery.fn 上,根据调用函数的对象不同决定。例如:

:(function($) {
    $.fn.extend({ // 参数对象
        'color': function(){ // 对象的属性将会复制到 $.fn 上
            // 插件代码
        },
        'border': function () {
            // 插件代码
        }
    });
})(jQuery);

jQuery 本身的代码中,也大量使用了 $.extend 方法。这个方法可以和 Object.assign() 对照学习。

资料:
- 【深入浅出jQuery】源码浅析–整体架构
- jQuery源码解析(架构与依赖模块)
- jQuery API 3.3.1 速查表
- 《锋利的jQuery》
- javascript之Object.assign()痛点

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值