欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

jQuery源码剖析--jQuery入口函数-init实现

程序员文章站 2022-07-13 12:34:55
...

通过$工厂,最终到达了init构造函数,所有实例的初始化过程都在这里实现,所以把这里称之为入口函数。

jQuery入口函数-init实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <a class="a">1</a>
    <a class="a">2</a>
    <a class="a">3</a>
    <a class="a">4</a>
</div>
<script>
    /*
     * jq入口对不同参数处理的规律:
     * 1、传入null、undefined、0、NaN、''返回空对象( 即空实例 )
     * 2、传入字符串,那么需要判断是html片段 还是 其它,
     * 如果是片段,则创建对应的DOM,然后添加到实例身上;
     * 否则按照选择器获取页面中的DOM,然后把获取到的DOM添加到实例身上。
     * 3、如果是数组或许伪数组,那么把每一项分别添加到实例身上。
     * 4、除了上面的数据类型,剩余的,统一添加到实例身上。
     * */

    // 判断是不是html片段
    init.isHTML = function (html) {

        // 如果是空类型的,直接返回false
        if (!html) {
            return false;
        }

        // 如果字符串的第一个字母是<,最后一个字母是>,并且length >= 3,就可以认为是html片段。
        if (html.charAt(0) == '<' && html.charAt(html.length - 1) == '>' && html.length >= 3) {
            return true;
        }

        return false;
    };

    // 去掉字符串首尾空白字符
    init.trim = function (str) {

        // 不是字符串就不处理了
        if (typeof str !== 'string') {
            return str;
        }

        // 优先使用内置的trim方法
        if (str.trim) {
            return str.trim();
        }

        // 把首尾空白字符替换为空,然后返回
        return str.replace(/^\s+|\s+$/g, '');
    };

    // 判断是不是函数
    init.isFunction = function (fn) {

        if (typeof fn == 'function') {
            return true;
        }

        return false;
    },

        // 判断是不是window
            init.isWindow = function (w) {

                if (w.window == w) {
                    return true;
                }

                return false;

            },

        // 判断是不是伪数组或真数组
        init.isLikeArray = function( arr ) {

            // 过滤函数和window,以及非对象的其他数据
            if ( init.isFunction( arr ) || init.isWindow( arr ) || typeof arr !== 'object' ) {
                return false;
            }

            // 判断是不是真数组
            if ( ({}).toString.call( arr ) == '[object Array]' ) {
                return true;
            }

            // 判断是不是伪数组
            // arr必须有length,在这个基础上,要么length为0,要么有length - 1这个属性值
            if ( ('length' in arr) && ( (arr.length === 0) || (arr.length - 1 in arr) ) ) {
                return true;
            }

            return false;
        };

    function init(selector) {

        // 传入null、undefined、0、NaN、''返回空对象( 即空实例 )
        if (!selector) {
            return this;
        }

        // 传入字符串,那么需要判断是html片段 还是 其它
        else if (typeof selector == 'string') {

            // 为了用户友好体验,先去掉首尾空白字符
            selector = init.trim(selector);

            // 如果是片段,则创建对应的DOM,然后添加到实例身上,
            // 如果字符串的第一个字母是<,最后一个字母是>,并且length >= 3,就可以认为是html片段。
            if (init.isHTML(selector)) {

                /*
                 * 创建的思路:
                 * 1、先创建一个临时的div容器
                 * 2、设置这个div的innerHTML为html片段,
                 * 这些片段就自动转变为了div的子元素,
                 * 3、然后遍历div的子元素分别添加this身上,记住给实例补充length属性值,
                 *  可以使用数组的push来给实例添加,同时可以使用apply简化遍历过程。
                 * */
                var tempDiv = document.createElement('div');
                tempDiv.innerHTML = selector;
                [].push.apply(this, tempDiv.childNodes);
                return this;
            }

            // 否则按照选择器获取页面中的DOM,然后把获取到的DOM添加到实例身上
            else {

                /*
                 * 实现的思路:
                 * 1、使用querySelectorAll获取页面中的元素
                 * 2、然后遍历获取到所有元素分别添加this身上,记住给实例补充length属性值,
                 * 可以使用数组的push来给实例添加,同时可以使用apply简化遍历过程。
                 * */
                try {
                    var nodes = document.querySelectorAll(selector);
                    [].push.apply(this, nodes);
                    return this;
                } catch (e) {
                    this.length = 0;
                    return this;
                }
            }

        }

        /*
         * 判断是不是真假数组的思路:
         * 1、先把函数和window排除掉,
         * 2、然后通过toString来判断是不是真数组
         * 3、否则再判断是不是伪数组
         * 备注:下面的判断只用来判断是不是伪数组,不要用下面的判断条件判断真数组,
         *       例如:[ 0:1, , , ] 使用下面的判断,就会得到false,造成真数组的误判。
         * 3.1、 先看看这个对象有没有length属性,
         * 3.2、 如果有,看看length的值是不是为0,如果为0,OK是伪数组,
         * 3.3、 如果length的值不为0,看看这个数据有没有 length - 1这个属性,如果有,OK是伪数组。
         * 建议把这个是否是真假数组的判断封装为一个函数,在这里调用。
         * */
        else if (init.isLikeArray(selector)) {

            /*
             * 实现的思路:
             * 把真或伪数组中的每一项分别添加到实例身上,记住给实例补充length属性值,
             * 可以使用数组的push来给实例添加,同时可以使用apply简化遍历过程。
             * */
            [].push.apply(this, selector);
        }

        else {
            /*
             * 实现的思路:
             * 把这个参数直接添加到实例身上,length为1即可。
             * */
            this[0] = selector;
            this.length = 1;
        }

    }
    //---------------以下为测试部分------------------
    // 测试html片段
    /*var $spans = new init('<span>123</span>放松地放量加速离开的<span>321</span>');
     console.log( $spans );
     var $divs = new init('<div><span>sdsfsdfs</span><span>dgdfgdf</span></div>');
     document.body.appendChild( $spans[0] );
     document.body.appendChild( $divs[0] );*/

    // 测试选择器---
    /*var $as = new init('a');
     console.log( $as );
     document.body.appendChild( $as[0] );

     var $spans = new init('span');
     console.log( $spans );

     var $$ = new init('##dsfsd**');
     console.log( $$ );*/

    //        var a = new init([1,2,3]);
    //        console.log(a);
    var a = new init([1,2,3,4]);
    console.log(a);
    //
    //        console.log(init.isLikeArray([1, ,3]));
    //        console.log(init.isLikeArray({length: 0}));
    //        console.log(init.isLikeArray({length: 3, 0: 1, 1: 2, 2: 3}));
    //        console.log(init.isLikeArray({length: 10, 9: 999}));
    //
    //
    //        console.log(init.isLikeArray({0: 1, 1: 2, 2: 3}));
    //        console.log(init.isLikeArray({length:5}));
    //        console.log(init.isLikeArray({length:5, 0: 1, 1: 2, 2: 3}));

</script>
</body>
</html>