jquery 源码分析四(下)

接下去分析那个extend块,接下来是一个each函数,它对传入的数组中的每个值进行特定处理,根据返回值确定操作(明确返回 false则停止循环)

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;
                }
            }
        }

    // 不需要传入args时,这是一种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;
}

trim函数主要是用来去除字符串首尾的空格,优先使用浏览器中自带有的方法。makeArray则是将传入的一或两个参数转成数组返回,看源码分析如下:

trim: trim && !trim.call("\uFEFF\xA0") ?
    function( text ) {
        return text == null ?
            "" :
            trim.call( text );
    } :
    // 优先使用自带的trim
    // 否则就返回自己设置的trim函数
    function( text ) {
        return text == null ?
            "" :
            ( text + "" ).replace( rtrim, "" );   
                // rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
    },

makeArray: function( arr, results ) {
    var ret = results || [];

    if ( arr != null ) {
        // 当arr为数组或类数组时,用merge(后面就会分析到)
        if ( isArraylike( Object(arr) ) ) {
            jQuery.merge( ret,
                typeof arr === "string" ?
                [ arr ] : arr
            );
        } else {
           // 否则,就直接将arr作为一个元素添加到ret作为最后一项
            push.call( ret, arr );
        }
    }

    return ret;
}

inArray是用来判断从指定位置其某个元素是否在一个array中,merge是将后一个arr融合到前一个arr中(当然,也可能是类数组)

inArray: function( elem, arr, i ) {
    var len;

    if ( arr ) {
                // 优先使用自带的indexOf
        if ( indexOf ) {
            return indexOf.call( arr, elem, i );
        }

        len = arr.length;
        i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;

        for ( ; i < len; i++ ) {
            if ( i in arr && arr[ i ] === elem ) {
                return i;
            }
        }
    }

    return -1;
},

merge: function( first, second ) {
    var len = +second.length,
        j = 0,
        i = first.length;

    while ( j < len ) {
        first[ i++ ] = second[ j++ ];
    }

    // 为了兼容一些会返回length为NaN的情况的类数组(NodeList.....在某些浏览器中)
    if ( len !== len ) {
        while ( second[j] !== undefined ) {
            first[ i++ ] = second[ j++ ];
        }
    }

    first.length = i;

    return first;
},

grep作用是一个过滤的效果,对每隔元素执行一遍传入的函数,满足要求的就放入结果中。作为第三个invert参数,是为了设置是函数返回true还是false时才算通过过滤。 如果 ‘invert‘ 为 false ,则函数返回数组中由过滤函数返回 true 的元素,当‘invert‘为 true,则返回过滤函数中返回 false 的元素集。

grep: function( elems, callback, invert ) {
    var callbackInverse,
        matches = [],
        i = 0,
        length = elems.length,
        callbackExpect = !invert;

    // 循环整个elems,对每个都进行callback函数的运行
    // 根据invert筛选结果
    for ( ; i < length; i++ ) {
        callbackInverse = !callback( elems[ i ], i );
        if ( callbackInverse !== callbackExpect ) {
            matches.push( elems[ i ] );
        }
    }

    return matches;
}

map和each类似,不同的是map会对每一项进行循环,不会因为返回值的问题而停止,同时会将所有非null的返回值组成数组返回。

map: function( elems, callback, arg ) {
    var value,
        i = 0,
        length = elems.length,
        isArray = isArraylike( elems ),
        ret = [];

    // 如果是数组或类数组,就用i递增循环
    if ( isArray ) {
        for ( ; i < length; i++ ) {
            value = callback( elems[ i ], i, arg );

            if ( value != null ) {
                ret.push( value );
            }
        }

    // 否则,就认为是object,用for..in方法
    } else {
        for ( i in elems ) {
            value = callback( elems[ i ], i, arg );

            if ( value != null ) {
                ret.push( value );
            }
        }
    }

    // 返回数组副本,这样对新数组的修改不会影响到旧数组
    return concat.apply( [], ret );
}

proxy是一个可以改变执行函数上下文环境的函数,可以通过$.proxy(function(){},context)实现。(例:$( "#test" ).on( "click", $.proxy( me.test, me ) ) )。

proxy: function( fn, context ) {
    var args, proxy, tmp;
        //确定fn和context确切值
    if ( typeof context === "string" ) {
        tmp = fn[ context ];
        context = fn;
        fn = tmp;
    }

    // 若fn不是函数,则直接返回
    if ( !jQuery.isFunction( fn ) ) {
        return undefined;
    }

    // 得到要传入的参数
    args = slice.call( arguments, 2 );
    proxy = function() {
        //args为在proxy中定义的变量,而arguments则是执行时会有的变量(> <解释不清楚...来个例子)
       //$( "#test" ).on( "click", $.proxy( me.test, me ) )运行时,arguments为[jQuery.events]
        return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
    };

    // 设置唯一的guid,这样可以在后期移除
    proxy.guid = fn.guid = fn.guid || jQuery.guid++;

    return proxy;
},

最后一个是now函数,返回现在的时间

now: function() {
    return +( new Date() );
}

jquery 源码分析四(下),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。