jQuery的一些简单知识点(二)

1.把入口函数和框架融合,extend混入扩展静态方法,IE8中apply的兼容性问题

<body>
    <script>
        (function( w ) {

            // 工厂
            function jQuery( selector ) {
                return new jQuery.fn.init( selector );
            }

            // 替换原型 + 原型简称
            jQuery.fn = jQuery.prototype = {
                constructor: jQuery
            }

            // 给jQuery和原型分别添加extend方法,混入方式
            jQuery.extend = jQuery.fn.extend = function( obj ) {
                for ( var key in obj ) {
                    this[ key ] = obj[ key ];
                }
            }

            // 给jQuery添加一些静态方法
            jQuery.extend({

                // 去掉首尾空白字符
                trim: function( str ) {

                    // null、undefined、NaN、0、false、''
                    if ( !str ) {
                        return str;
                    }

                    // 优先使用原生的
                    if ( str.trim ) {
                        return str.trim();
                    }

                    return str.replace( /^\s+|\s+$/g, '');

                },

                // 判断是不是html片段
                isHTML: function( html ) {

                    // null、undefined、NaN、0、false、''
                    if ( !html ) {
                        return false;
                    }

                    // <.>
                    if( html.charAt(0) === '<' &&
                            html.charAt( html.length - 1 ) === '>' &&
                            html.length >= 3 ) {
                        return true;
                    }

                    return false;
                },

                // 判断是不是html片段
                _isHTML: function( html ) {
                    return !!html &&
                            html.charAt(0) === '<' &&
                            html.charAt( html.length - 1 ) === '>' &&
                            html.length >= 3;
                },

                // 判断是不是函数
                isFunction: function( fn ) {
                    if ( typeof fn === 'function' ) {
                        return true;
                    }
                    return false;
                },

                // 判断是不是函数
                _isFunction: function( fn ) {
                    return typeof fn === 'function';
                },

                // 判断是不是window
                isWindow: function( w ) {

                    // null、undefined、NaN、0、false、''
                    if( !w ) {
                        return false;
                    }

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

                    return false;
                },

                // 判断是不是window
                _isWindow: function( w ) {
                    return !!w && w.window === w;
                },

                // 判断是不是对象
                isObject: function( obj ) {

                    // 防止typeof对null的误判
                    if ( obj === null ) {
                        return false;
                    }

                    // 如果是object或function,那就是对象
                    if ( typeof obj === 'object' || typeof obj === 'function' ) {
                        return true;
                    }

                    return false;
                },

                // 判断是不是字符串
                isString: function( str ) {
                    if ( typeof str === 'string' ) {
                        return true;
                    }
                    return false;
                },

                // 判断是不是字符串
                _isString: function( str ) {
                    return typeof str === 'string';
                },

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

                    // Function、window、!Object
              if ( jQuery.isFunction( arr ) || jQuery.isWindow( arr ) || !jQuery.isObject( arr ) ) {
                        return false;
                    }

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

                    // 判断是不是伪数组
                    if ( 'length' in arr && ( arr.length === 0 || arr.length - 1 in arr ) ) {
                        return true;
                    }

                    return false;
                },

                ready: function( fn ) {

                    // 先统一判断DOMContentloaded有没有触发,
                    // 通过document.readyState === 'complete'判断
                    // 如果为true,fn可以直接调用。

                    // 如果为false,那么判断支不支持addEventListener,
                    // 如果支持,绑定DOMContentLoaded事件

                    // 如果不支持,使用attchEvent绑定onreadystatechang事件,
                    // 注意,需要在里面判断document.readyState === 'complete'才执行fn。
                    // 防止fn多次执行。

                    // DOM已经构造完毕,fn可以直接执行
                    if ( document.readyState === 'complete' ) {
                        fn();
                    }

                    // 如果DOM没有构造完毕,那么判断addEventListener是否兼容
                    else if( document.addEventListener ) {
                        document.addEventListener( 'DOMContentLoaded', fn );
                    }

                    // 如果不兼容addEventListener,那么采取attachEvent的方式,
                    // 同时事件变为了onreadystatechange,为了防止这个事件多次触发造成的fn多次执行,
                    // 所以需要一个包装函数来进行过滤。
                    else {
                        document.attachEvent( 'onreadystatechange', function() {
                            if( document.readyState === 'complete' ) {
                                fn();
                            }
                        } );
                    }
                }
            });

            // 这是真正的构造函数,同时把构造函数放在了原型中
            var init = jQuery.fn.init = function( selector ) {

                // null、undefined、NaN、0、false、''
                if ( !selector ) {
                    return this;
                }

                // function
                if ( jQuery.isFunction( selector ) ) {

                    // 打包给ready静态方法处理
                    jQuery.ready( selector );
                }

                // string ==> ( html || selector )
                else if( jQuery.isString( selector ) ) {

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

                    // html
                    if( jQuery.isHTML( selector ) ) {

                        // 利用一个临时的div来创建DOM,
                        // 然后把创建好的DOM依次push给实例。
                        var tempDiv = document.createElement( 'div' );
                        tempDiv.innerHTML = selector;
                        [].push.apply( this, tempDiv.childNodes );

                    }

                    // selector
                    else {

                        try {
                            [].push.apply( this, document.querySelectorAll( selector ) );
                        }catch(e) {
                            // 如果报错了,那么手动补一个length属性,代表没有获取到任何元素
                            this.length = 0;
                        }
                    }
                }

                // array || likeArray
                else if( jQuery.isLikeArray( selector ) ) {
                    //[].push.apply( this,  selector  ); 这里,如果selector是自己写的伪数组,而不是系统的伪数组,那么在IE8中会出错,所以我们采用了[].slice.call( selector ) ,把伪数组转变为真数组。
                    [].push.apply( this, [].slice.call( selector ) );
                }

                // 其它
                else {
                    this[0] = selector;
                    this.length = 1;
                }
            };

            // 替换init的原型为工厂的原型,这样外界就可以通过工厂给实例扩展方法
            init.prototype = jQuery.fn;

            // 暴露工厂和工厂的简称
            w.jQuery = w.$ = jQuery;

        }( window ));

        // 静态方法测试
        console.log($._isFunction([]));
        console.log($.isWindow( window ));
        console.log($.isLikeArray( { length: 5 } ));
        console.log($.isLikeArray( { length: 0 } ));

        // 入口测试
        console.log($([1, 2]));
        console.log($(' script'));
        console.log($(' <span>111</span><span>222</span> '));
        console.log($({ 0:document.body, length:1 }));

        // 测试入口对函数的支持
        $(function() {
            console.log($('a')); //再打印这一句
        });
        console.log($('bb'));    //先打印这一句
    </script>
    <div>
        <a>1</a>
        <a>2</a>
        <a>3</a>
    </div>
</body>

2.jQuery中静态方法Each(),数组的forEach(),以及自定义的each()的使用,以及each()中的this指向问题

    <script>
    var obj = {
        1: 'aaa',
        2: 'bbb',
        3: 'ccc'
    };
    var arr = ['xxx', 'yyy', 'zzz'];
    // jQuery中静态方法each的使用,及其中的this指向,this指的是每一个元素
    $.each(obj, function(key, val) {
        console.log(key, val, this);
    });
    $.each(arr, function(key, val) {
        console.log(key, val, this);
    });

    // arr的原型方法forEach的使用,注意参数顺序,以及this指向问题window
    arr.forEach(function(val, key) {
        console.log(val, key, this); //window
    });

    // function each(obj,fn){
    //  if ('length' in arr) {
    //      for(var i=0;i<obj.length;i++){
    //          fn(i,obj[i]);
    //      }
    //  }else{
    //      for(var key in obj){
    //          fn(key,obj[key]);
    //      }
    //  }
    // };
    // 自定义方法中的this也是指向window的
    // each(arr, function(key, val) {
    //     console.log(key, val, this); //window
    // });


    function each1(obj, fn) {
        if ('length' in arr) {
            for (var i = 0; i < obj.length; i++) {
                fn.call(obj[i], i, obj[i]);
            }
        } else {
            for (var key in obj) {
                fn.call(obj[key], key, obj[key]);
            }
        }
    };
    // 自定义方法中的this也是指向每一元素对应的对象
    each1(arr, function(key, val) {
        console.log(key, val, this); //
    });
    </script>

3.遍历中断,这里最好打个断点看下函数的执行流程,加强对回调函数的理解。


    function each1(obj, fn) {
        if ('length' in obj) {
            for (var i = 0; i < obj.length; i++) {
                if (fn.call(obj[i], i, obj[i]) === false) {
                    break;
                }
            }
        } else {
            for (var key in obj) {
                if (fn.call(obj[key], key, obj[key])===false) {
                    break;
                }
            }
        }
    };

    // 自定义方法中的this也是指向每一元素对应的对象
    each1(obj, function(key, val) {
        if (val == 'bbb') {
            return false;
        }
        console.log(key, val, this); //
    });
    打个比方,再调用each1()时,传入了obj和一个函数,这就好比是大boss派了一个保镖去门口监视路过门口的行人obj,保镖的任务是把每个人的编号和T-shirt上的信息告诉大boss,大boss接受到每一个人T-shirt上的信息,发现有个人的T-shirt上写的是‘bbb’,通过对讲机告诉保镖,停止监视false,立刻break.

4.模仿jQuery中map()的实现

    <script>

        var obj = { a: 111, b: 222, c: 333, d: 444 };
        var arr = [ 'aaa', 'bbb', 'ccc', 'dddd' ];


        /*
        * jQ的map方法,用来遍历对象或者数组,
        * 然后把遍历到了val和key值传给回调,
        * 最后收集回调的返回值,构成新数组返回。
        * */

        /*console.log($.map(obj, function (val, key) {
            console.log(val, key, this);
            return val;
        }));*/


        // map实现
        function map( obj, fn ) {

            /*
             * 1、先判断obj是不是数组或者伪数组,
             * 2、如果是,则通过i的方式遍历这个对象
             * 3、如果不是,则通过for in的方式遍历这个对象
             * 4、在遍历的过程中,把每一次遍历到key和val分别传给回调。
             * 5、在给回调传参的时候,需要收集回调的返回值,最后把所有的返回值构成新数组返回。
             * */
            var i, len, key, result = [];

            if( 'length' in obj ) {
                for ( i = 0, len = obj.length; i < len; i++ ) {
                    result.push( fn.call( obj[ i ], obj[ i ], i ) );
                }
            }else {
                for ( key in obj ) {
                    result.push( fn.call( obj[ key ], obj[ key ], key ) );
                }
            }

            return result;
        }

        console.log(map(obj, function (val, key) {
            console.log(val, key, this);
//            return val / 100;
        }));

    </script>





           // 给jQuery的静态方法加入map和each方法,同时,拥有在jQuery的原型中有这两个变量
            jQuery.extend({

                // 遍历对象或类数组
                each: function( obj, fn ) {
                    var i, len, key;

                    if ( jQuery.isLikeArray( obj ) ) {
                        for ( i = 0, len = obj.length; i < len; i++ ) {
                            if ( fn.call( obj[ i ], i, obj[ i ] ) === false ) {
                                break;
                            }
                        }
                    }else {
                        for ( key in obj ) {
                            if ( fn.call( obj[ key ], key, obj[ key ] ) === false ) {
                                break;
                            }
                        }
                    }

                    return obj;
                },

                // map实现
                map: function( obj, fn ) {

                    /*
                     * 1、先判断obj是不是数组或者伪数组,
                     * 2、如果是,则通过i的方式遍历这个对象
                     * 3、如果不是,则通过for in的方式遍历这个对象
                     * 4、在遍历的过程中,把每一次遍历到key和val分别传给回调。
                     * 5、在给回调传参的时候,需要收集回调的返回值,最后把所有的返回值构成新数组返回。
                     * */
                    var i, len, key, result = [];

                    if( 'length' in obj ) {
                        for ( i = 0, len = obj.length; i < len; i++ ) {
                            console.log('*****',fn.call( obj[ i ], obj[ i ], i ));
                            result.push( fn.call( obj[ i ], obj[ i ], i ) );
                        }
                    }else {
                        for ( key in obj ) {
                            result.push( fn.call( obj[ key ], obj[ key ], key ) );
                        }
                    }
console.log('-------',result);
                    return result;
                },
                ...
            });

                // 替换原型 + 原型简称
            jQuery.fn = jQuery.prototype = {
                // 遍历实例
                each: function( fn ) {
                    return jQuery.each( this, fn );
                },

                // 通过实例得到一个新数组
                map: function( fn ) {
                    return jQuery.map( this, fn );
                },
                ...
               }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值