zoukankan      html  css  js  c++  java
  • JQuery源码解析-JQuery的工具方法(4)

    下面对这些方法进行讲解

      each():遍历集合

      trim():去前后空格

      makeArray():类数组转换真数组

      inArray():数组版indexOf

      merge():合并数组

      grep():过滤新数组

      map():映射新数组

    each方法:

    each是遍历集合用的方法,也是一个加强版的循环操作。例如:

     var arr = { Name: 'jam', Age: 15 };
            $.each(arr, function (key, val) {
                console.log(key + ":" + val); //Name:jam Age:15
            })

    each方法不仅可以对数组,类数组进行遍历,还可以对json对象进行遍历。源码:

    // args is for internal usage only
        each: function( obj, callback, args ) {
            var value,
                i = 0,
                length = obj.length,
                isArray = isArraylike( obj );
    
            if ( args ) {
                if ( isArray ) {
                    for ( ; i < length; i++ ) {
                        value = callback.apply( obj[ i ], args );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                } else {
                    for ( i in obj ) {
                        value = callback.apply( obj[ i ], args );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                }
    
            // A special, fast, case for the most common use of each
            } else {
                if ( isArray ) {
                    for ( ; i < length; i++ ) {
                        value = callback.call( obj[ i ], i, obj[ i ] );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                } else {
                    for ( i in obj ) {
                        value = callback.call( obj[ i ], i, obj[ i ] );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                }
            }
    
            return obj;
        },

    可以看到这个方法,实际接收了三个参数,最后一个参数为内部使用,我们在外部使用的时候只需要两个参数就够了。

    首先第一个部分是声明内部用到的变量:

           var value,
                i = 0,
                length = obj.length,
                isArray = isArraylike( obj );

    前三个参数没什么说的,主要看一下isArray这个变量,通过isArraylike这个方法,可以判断是否为数组或类数组,如果是,则返回true。

    接下来进行判断args,用来区分是否为内部调用:

    if ( args ) {
    //源码
    } else {
    //源码
    }

    先看一下满足条件里面的源码,也就是内部使用的都做了什么:

          if ( isArray ) {
                    for ( ; i < length; i++ ) {
                        value = callback.apply( obj[ i ], args );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                } else {
                    for ( i in obj ) {
                        value = callback.apply( obj[ i ], args );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                }

    先看传入的对象是否为数组或类数组,如果是则遍历这个对象,然后将当前项和参数传入回调方法,进行回调。

    如果不满足条件,那么就是json对象,所以进行for in遍历,然后执行相同的操作,这里看到回调方法会返回一个值,如果为false,则跳出循环,所以如果想则each方法跳出循环是,直接return false;就可以了

    接下来看一下我们平时使用的代码:

          if ( isArray ) {
                    for ( ; i < length; i++ ) {
                        value = callback.call( obj[ i ], i, obj[ i ] );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                } else {
                    for ( i in obj ) {
                        value = callback.call( obj[ i ], i, obj[ i ] );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                }

    代码和上面内部使用的没有太大的区别,只不过调用回调方法时传入的参数不一样,另外这个方法使用了call,内部方法使用的是apply,也就是说在jQuery内部,传入的参数个数可能不一样,而我们使用时,只需要传入两个就可以了。

    trim方法:

    trim 方法是对字符串去前后空格的方法,在平时经常使用这个方法,源码:

    trim: function( text ) {
            return text == null ? "" : core_trim.call( text );
        },

    源码很简单,如果传入的字符串为null或undefined,则直接返回空字符就可以了,如果有值,则直接调用es5的trim方法就行。这个core_trim指向的是原生的trim方法。

    core_trim = core_version.trim,

     makeArray方法:

    这个方法可以将类数组转换成真正的数组,方法有两个参数,如果传入第二个参数,则返回类数组。

    页面中有三个div,分别是1、2、3

    window.onload = function () {
                var divs = document.getElementsByTagName('div');
                console.log($.makeArray(divs));//[div, div, div]
            }

    传入第二个参数时:

      window.onload = function () {
                var divs = document.getElementsByTagName('div');
                console.log($.makeArray(divs, { length: 1 }));//Object {1: div, 2: div, 3: div, length: 4}
            }

    下面看一下源码:

    // results is for internal usage only
        makeArray: function( arr, results ) {
            var ret = results || [];
    
            if ( arr != null ) {
                if ( isArraylike( Object(arr) ) ) {
                    jQuery.merge( ret,
                        typeof arr === "string" ?
                        [ arr ] : arr
                    );
                } else {
                    core_push.call( ret, arr );
                }
            }
    
            return ret;
        },

    首先检查是否传入第二个参数,如果为空,则给一个空数组。然后查看参数是否为数组或类数组。注意这里:

    if ( isArraylike( Object(arr) ) ) {

    这里将参数外面包一层object,是将参数转换为对象,如果传入数字,则返回false,如果传入的是字符串,那么会返回true,因为字符串被转成对象了,并且有长度。

    然后通过merge方法进行附加,把传入的参数合并到ret中。

    如果不为数组或类数组,则直接用数组的push将参数附加到数组中即可。

    inArray方法:

    这个方法和数组的indexof功能一样,返回查找值的索引:

           var arr = ['a,', 'b', 'c'];
            console.log($.inArray('c',arr,0)); //2

    源码如下:

    inArray: function( elem, arr, i ) {
            return arr == null ? -1 : core_indexOf.call( arr, elem, i );
        },

    源码很简单,第一个参数是要查找的值,第二个是对象,第三个是从第几项开始查找。然后调用数组的indexOf方法。

    merge方法:

    这个方法经常用到,可以将两个数组合并成一个。

           var arr1 = ['a', 'b'];
            var arr2 = ['c', 'd'];
            var arr3 = $.merge(arr1, arr2);
            console.log(arr3);//["a", "b", "c", "d"]

    另外第二个参数还可以传入一个类数组。

      var arr1 = ['a', 'b'];
            var arr2 = { 0: 'c', 1: 'd'};
            var arr3 = $.merge(arr1, arr2);
            console.log(arr3);//["a", "b", "c", "d"]

    当第一个参数为类数组时:

            var arr1 = ['a', 'b'];
            var arr2 = { 0: 'c', 1: 'd' };
            var arr3 = $.merge(arr2, arr1);
            console.log(arr3);////Object {0: "c", 1: "d", 2: "a", 3: "b", length: 4}

    看到,当第一个参数为类数组时,返回的也就类数组的形式。

    源码如下:

    merge: function( first, second ) {
            var l = second.length,
                i = first.length,
                j = 0;
    
            if ( typeof l === "number" ) {
                for ( ; j < l; j++ ) {
                    first[ i++ ] = second[ j ];
                }
            } else {
                while ( second[j] !== undefined ) {
                    first[ i++ ] = second[ j++ ];
                }
            }
    
            first.length = i;
    
            return first;
        },

    先获取两个参数的长度,如果第二个参数有值,并且是数字类型的话,那么直接遍历第二个数组,附加到第一个上即可。

    如果第二个参数没有长度,也就是可能是json对象,那么直接遍历,这里需要注意,即使是json对象,那么里面的属性名也必须是1、2、3。例如:

      var arr2 = { 0: 'c', 1: 'd' };

    最后更新长度,并返回合并后的对象。

    grep方法:

    grep方法是对数组进行筛选,只返回满足条件的值。例如:

       var arr = [1, 2, 3, 4, 5];
            arr=$.grep(arr,function(v,i){
                return v>2;
            });
            console.log(arr);//[3, 4, 5]

    另外这个方法还接受第三个参数,如果传入,那么代表筛选条件进行反转。例如上面的例子中,如果传入第三个参数,那么筛选的条件实际业绩刘是v<=2。

    源码:

    grep: function( elems, callback, inv ) {
            var retVal,
                ret = [],
                i = 0,
                length = elems.length;
            inv = !!inv;
    
            // Go through the array, only saving the items
            // that pass the validator function
            for ( ; i < length; i++ ) {
                retVal = !!callback( elems[ i ], i );
                if ( inv !== retVal ) {
                    ret.push( elems[ i ] );
                }
            }
    
            return ret;
        },

    先对判断第三个参数是否传入,如果没传,那么!!inv则为false。然后遍历传入的对象,并将每项都传入回调方法中,最后利用inv进行控制,当inv为false的时候,也就是没传入第三个参数时,

    那么回调函数返回结果为true时,则添加到返回的ret中,这里用到:

     if ( inv !== retVal ) {
                    ret.push( elems[ i ] );
                }

    这个判断,使代码非常灵活。

    map方法,这个方法是返回操作后的一个新数组,例如:

      var arr = [1, 2, 3, 4, 5];
            arr=$.map(arr,function(v,i){
                return v * 2;
            });
            console.log(arr);//[2, 4, 6, 8, 10]

    使用很简单,来看下源码:

    // arg is for internal usage only
        map: function( elems, callback, arg ) {
            var value,
                i = 0,
                length = elems.length,
                isArray = isArraylike( elems ),
                ret = [];
    
            // Go through the array, translating each of the items to their
            if ( isArray ) {
                for ( ; i < length; i++ ) {
                    value = callback( elems[ i ], i, arg );
    
                    if ( value != null ) {
                        ret[ ret.length ] = value;
                    }
                }
    
            // Go through every key on the object,
            } else {
                for ( i in elems ) {
                    value = callback( elems[ i ], i, arg );
    
                    if ( value != null ) {
                        ret[ ret.length ] = value;
                    }
                }
            }
    
            // Flatten any nested arrays
            return core_concat.apply( [], ret );
        },

    方法接收三个参数,第三个参数是jQuery内部使用的,平时一般用不到。

    接下来判断传入的参数是否为数组或类数组,如果是:

          for ( ; i < length; i++ ) {
                    value = callback( elems[ i ], i, arg );
    
                    if ( value != null ) {
                        ret[ ret.length ] = value;
                    }
                }

    遍历这个对象,并将每项传入回调方法中,最后将回调方法的返回值放入定义好的ret中。

    如果不是数组或类数组:

          for ( i in elems ) {
                    value = callback( elems[ i ], i, arg );
    
                    if ( value != null ) {
                        ret[ ret.length ] = value;
                    }
                }

    利用for in 循环这个对象每项,并将每项传入回调方法中,最后将回调方法的返回值放入定义好的ret中。

    最后返回这个新对象:

        // Flatten any nested arrays
            return core_concat.apply( [], ret );

    可以看到这里使用到了数组的concat方法,而不是直接返回ret,这是因为这个方法不想返回嵌套数组的结构,例如:

    var arr = [1, 2, 3, 4, 5];
            arr=$.map(arr,function(v,i){
                return [v * 2];
            });
            console.log(arr);//[2, 4, 6, 8, 10]

    如果回调方法返回的就是数组,那么经过这个处理还是返回一个数组的结构,如果将源码中的最后一句替换掉:

         // Flatten any nested arrays
            //return core_concat.apply( [], ret );
            return ret;

    那么返回的是:[[2], [4], [6], [8], [10]]这种形式了。

      

  • 相关阅读:
    [C++]怎么将.h和.cpp文件分别放在不同的目录
    [C++]VAssistX文件头添加注释功能设置
    教程-Delphi调用百度地图API(XE8+WIN7)
    WebBrowser的各种使用方法(未完待续)(XE8+WIN7)
    Android教程-夜神模拟器连接IDE更新让Delphi发现你的手机或夜神模拟器
    首尔甜城常用电话
    Android问题-DelphiXE5开发Andriod连接Webservice乱码问题
    点乘的使用
    [转]脏读,不可重复读,幻读的理解
    Unity3D刚体不同力的测试(ForceMode,AddForce,RelativeAddForce)
  • 原文地址:https://www.cnblogs.com/y8932809/p/5892056.html
Copyright © 2011-2022 走看看