前端开发系列073-JQuery篇之源码核心

本文介绍jQuery 源码的主体结构和关键细节。

jQuery是前端开发中绕不开的一个框架,在React和Vue等框架出现前,jQuery无疑是前端开发主流技术栈中不可或缺的框架。它为我们提供了强大的DOM操作可靠的事件处理机制简单的动画特效完善的Ajax网络请求好用的工具方法以及超前的链式调用等能力,阅读jQuery框架的源码是必要的。

总体来说,jQuery框架的源码并不复杂,主要几个版本的代码都保持在1W行左右的水准,下面列出jQuery框架最核心的结构。

/* 001-外层是闭包(立即执行函数) */
(function() {
    "use strict";   /* 默认开启严格模式 */
    let version = "1.0.0";   /* 设置当前框架的版本号 */

    /* 002-声明jQuery工厂函数 */
    let jQuery = function(selector) {

        /* 构造函数:jQuery.fn.init */
        /* 返回实例:jQuery.fn.init 构造函数创建出来的实例对象 */
        return new jQuery.fn.init(selector);
    }

    /* 003-设置jQuery的原型对象 */
    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        init: function() {},
        eq() {},
        get() {},
        first() {},
        last() {},
        toArray() {}
    }

    /* 004-设置原型对象共享(为了让init的实例对象可以访问jQuery原型成员) */
    jQuery.fn.init.prototype = jQuery.fn;

    /* 005-插件方法和插件机制 */
     jQuery.fn.extend = jQuery.extend = function(o) {
        for (let key in o) {
            this[key] = o[key];
        }
    }

    jQuery.extend({});
    jQuery.fn.extend({});

    /* 006-把jQuery和$暴露出去 */
    window.jQuery = window.$ = jQuery;
})();

这里再给出jQuery框架中核心入口函数init方法实现的简单版本以及插件机制和核心方法的简单实现。

/* 001-外层是闭包(立即执行函数) */
(function() {
    /* 002-默认开启严格模式 */
    "use strict";

    /* 003-设置当前框架的版本号 */
    let version = "1.0.0";

    /* 004-声明jQuery工厂函数 */
    let jQuery = function(selector) {

        /* 构造函数:jQuery.fn.init */
        /* 返回:jQuery.fn.init构造函数创建出来的实例对象 */
        return new jQuery.fn.init(selector);
    }

    /* 005-设置jQuery的原型对象 */
    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        init: function(selector) {

            /* 如果参数为假 */
            if (!selector) {
                return this;
            }
            /* 如果参数是函数 */
            if ($.isFunction(selector)) {
                document.addEventListener("DOMContentLoaded", selector)
            }
            /* 如果参数是字符串 */
            else if ($.isString(selector)) {
                /* 标签字符串 "<div>测试</div>" "<a>"*/
                if ($.isHTMLSting(selector)) {
                    let ele = document.createElement("div");
                    ele.innerHTML = selector;
                    [].push.apply(this, ele.children)
                }
                /* 选择器字符串  "div"  ".box"*/
                else {
                    [].push.apply(this, document.querySelectorAll(selector));
                }
            }
            /* 如果参数是数组或者是伪数组 */
            else if ($.isArray(selector) || $.isLikeArray(selector)) {
                //把selector中所有的元素依次添加到this中并且更新length
                [].push.apply(this, selector);
            } else {
                this[0] = selector;
                this.length = 1;
            }

        },
        eq(index) {
            return $(this.get(index));
        },
        get(index) {
            return index >= 0 ? this[index] : this[this.length + index];
        },
        first() {
            return this.eq(0);
        },
        last() {
            return this.eq(-1);
        },
        toArray() {
            return [].slice.call(this);
        }
    }

    /* 工具方法的处理 */
    /* jQuery插件机制 */
    jQuery.fn.extend = jQuery.extend = function(o) {
        for (let key in o) {
            this[key] = o[key];
        }
    }

    jQuery.extend({
        isString: function(str) {
            return typeof str == "string";
        },
        isFunction: function(fn) {
            return typeof fn == "function";
        },
        isObject: function(obj) {
            return typeof obj == "object" && obj != null;
        },
        isHTMLSting: function(htmlStr) {
            return htmlStr.charAt(0) == "<" && htmlStr.charAt(htmlStr.length - 1) == ">" && htmlStr.length >= 3
        },
        isArray: function(arr) {
            if (Array.isArray) {
                return Array.isArray(arr);
            } else {
                return Object.prototype.toString.call(arr) == "[object Array]";
            }
        },
        isLikeArray: function(likeArr) {
            return typeof $.isObject(likeArr) && "length" in likeArr && likeArr.length - 1 in likeArr;
        }
    });

    jQuery.extend({
        xxxx() {
            console.log("----");
        }
    })

    jQuery.fn.extend({
        css: function() {},
        text: function() {},
        html: function() {}
    });

    jQuery.fn.extend({
        on: function(type, handler) {
            // $("button").on("click", function() {
            //     console.log("click", this);
            // })  
            /* > 给所有选中的标签(this)都添加指定类型的事件,当事件触发的时候要执行事件处理函数 */
            for (let i = 0, len = this.length; i < len; i++) {
                this[i].addEventListener(type, handler);
            }
        },
        click: function(handler) {
            this.on("click", handler);
        },
        mouseenter: function(handler) {
            this.on("mouseenter", handler);
        },
        mouseleave: function(handler) {
            this.on("mouseleave", handler);
        }
    });

    jQuery.fn.extend({
        css() {},
        attr() {},
        addClass() {},
        removeClass() {},
        toggleClass() {},
        append() {}
    })

    /* 006-设置原型对象共享(为了让init的实例对象可以访问jQuery原型成员) */
    jQuery.fn.init.prototype = jQuery.fn;

    /* 007-把jQuery和$暴露出去 */
    window.jQuery = window.$ = jQuery;
})();

posted on 2022-12-15 08:56  文顶顶  阅读(35)  评论(0编辑  收藏  举报

导航