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]]这种形式了。

  

时间: 2024-11-10 07:29:58

JQuery源码解析-JQuery的工具方法(4)的相关文章

JQuery源码解析-JQuery的工具方法(3)

这篇文章主要对下面这几个方法进行解释 error();抛出异常 parseHTML():解析节点 parseJSON():解析JSON parseXML:解析XML noop():空函数 globalEval():全局解析JS camelCase():转驼峰 nodeName():是否为指定节点(内部) error:方法: error方法的作用是抛出一个自定义异常,内部直接调用了原生解释的throw new Error error: function( msg ) { throw new Err

JQuery源码解析-JQuery的工具方法(2)

这篇对下面的方法进行讲解: isFunction():是否为函数 isArray():是否为数组 isWindow():是否为window isNumeric()是否为数字 type():判断数据类型 isPlainObject():是否为对象自变量 isEmptyObject():是否为空的对象 isFunction方法: 这个方法很简单,判断对象是否为函数,返回bool类型,看一下源码: // See test/unit/core.js for details concerning isFu

JQuery源码解析-JQuery的工具方法(5)

下面对最后这几个方法进行讲解. guid():唯一表示(内部) proxy():改变this指向 access(): 多功能值操作 now():当前时间 swap():css交换(内部) guid: 这个属性是对事件进行控制的,例如每次对dom元素进行绑定事件的时候,会通过这个属性进行绑定,这个属性每次自增,产生一个唯一的标示,所以对dom元素进行事件解绑等操作的时候,通过这个属性就可以找到. 源码: // A global GUID counter for objects guid: 1, p

jQuery方法源码解析--jQuery($)方法(一)

jQuery方法源码解析--jQuery($)方法 注: 1.本文分析的代码为jQuery.1.11.1版本,在官网上下载未压缩版即可 2.转载请注明出处 jQuery方法: 这个方法大家都不陌生,在使用过程中,它还有另外一个名字,美元符号:$,$(...)其实就是jQuery(...); 它有很多种用法,通常都返回一个jquery对象,也可以作为$(document).ready(...);的简写形式,分析之前先看一下jQuery都有什么用法. 1.jQuery( selector [, co

十七.jQuery源码解析之入口方法Sizzle(1)

函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: 1.解析选择器表达式,解析出块表达式和关系符. 2.如果存在位置伪类,则从左向右查找: a.查找第一个块表达式匹配的元素集合,得到第一个上下文元素集合. b.遍历剩余的块表达式和块间关系符,不断缩小上下文元素集合. 3.否则从右向左查找: a.查找最后一个块表达式匹配的元素集合,得到候选集,映射集

jQuery源码解析(jQuery对象的实例属性和方法)

1.记录版本号 以及 修正constructor指向 jquery: core_version, constructor: jQuery, 因为jQuery.prototype={ ... } 这种写法将自动生成的jQuery.prototype.constructor属性覆盖删除,所以需要重新修正(指向其构造函数 jQuery).2.init() 初始化方法: init()方法最终返回的是this -jQuery(其实是jQuery.prototype.init)方法的实例对象. 实例对象继承

jquery源码解析:代码结构分析

本系列是针对jquery2.0.3版本进行的讲解.此版本不支持IE8及以下版本. (function(){ (21, 94)     定义了一些变量和函数,   jQuery = function(){}; (96,283)   给jQuery对象添加一些属性和方法(实例方法,通过$("div")这类的jQuery实例对象来调用) (285,347)   extend : jQuery的继承方法 (349,817)   jQuery.extend():扩展一些工具方法(静态方法,直接通

五.jQuery源码解析之jQuery.extend(),jQuery.fn.extend()

给jQuery做过扩展或者制作过jQuery插件的人这两个方法东西可能不陌生.jQuery.extend([deep],target,object1,,object2...[objectN]) jQuery.fn.extend([deep],target,object1,,object2...[objectN])这两个属性都是用于合并两个或多个对象的属性到target对象.deep是布尔值,表示是否进行深度合并,默认是false,不执行深度合并.通过这种方式可以在jQuery或jQuery.fn

四.jQuery源码解析之jQuery.fn.init()的参数解析

从return new jQuery.fn.init( selector, context, rootjQuery )中可以看出 参数selector和context是来自我们在调用jQuery方法时传过来的.那么selector和context都有哪些可能. 对于表格中的4~9行中的可能做具体分析. 如果selector是字符串,则首先检测是html代码还是#id. 126行的if语句:以"<"开头,以">"结尾,且长度>=3.则假设额这个是HT