zoukankan      html  css  js  c++  java
  • jquery1.7.2的源码分析(二)

    jquery.extend

    jQuery.extend = jQuery.fn.extend = function () {
    var options, name, src, copy, copyIsArray, clone,
    //target为传入的一个参数
        target = arguments[0] || {},
        i = 1,
    //传入参数的个数
        length = arguments.length,
    //首先默认为浅拷贝
        deep = false;
    // Handle a deep copy situation
    if (typeof target === "boolean") {
    //当第一个参数是布尔值
    deep = target;
    //target第二个参数
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
    }
    //当target不是object并且不是function
    if (typeof target !== "object" && !jQuery.isFunction(target)) {
    target = {};
    }
    // extend jQuery itself if only one argument is passed
    //当是一个参数的时候$.extend({ccc:function(){}})
    if (length === i) {
    //target为init对象
    target = this;
    --i;
    }
    for (; i < length; i++) {
    // Only deal with non-null/undefined values
    if ((options = arguments[i]) != null) { 
    // Extend the base object
        for (name in options) {
            src = target[name];
            copy = options[name];
    // Prevent never-ending loop
            if (target === copy) {
                continue;
            }
    //
    // Recurse if we're merging plain objects or arrays
    //深拷贝
            if (deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) )) {
                if (copyIsArray) {
                    copyIsArray = false;
    //判断原先的属性存在,存在后再判断是否是数组,不是的话赋值为空数组
                    clone = src && jQuery.isArray(src) ? src : [];
                } else {
    //判断原先的属性存在,存在后再判断是否是对象,不是的话赋值为空对象
                    clone = src && jQuery.isPlainObject(src) ? src : {};
                }
    // Never move original objects, clone them
                target[name] = jQuery.extend(deep, clone, copy);
    // Don't bring in undefined values
            } else if (copy !== undefined) {
    //将方法复制到当前对象
                target[name] = copy;
            }
        }
    }
    }
    // Return the modified object
    return target;
    };
    };
    

    jquery.extend的使用

    jQuery.extend({
        noConflict: function( deep ) {
            if ( window.$ === jQuery ) {
                window.$ = _$;
            }
            if ( deep && window.jQuery === jQuery ) {
                window.jQuery = _jQuery;
            }
            return jQuery;
        },
    // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
    // A counter to track how many items to wait for before
    // the ready event fires. See #6781
        readyWait: 1,
    // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                jQuery.readyWait++;
            } else {
                jQuery.ready( true );
            }
        },
    // Handle when the DOM is ready
        ready: function( wait ) {
    // Either a released hold or an DOMready/load event and not yet ready
    //wait=true且jQuery.readyWait-1取非为true 或者wait为false jQuery.isReady为false
            if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
    // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
    //当不存在body元素了,继续执行这个函数
                if ( !document.body ) {
                    return setTimeout( jQuery.ready, 1 );
                }
    // Remember that the DOM is ready
                jQuery.isReady = true;
    // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --jQuery.readyWait > 0 ) {
                    return;
                }
    // If there are functions bound, to execute
                readyList.fireWith( document, [ jQuery ] );
    // Trigger any bound ready events
                if ( jQuery.fn.trigger ) {
                    jQuery( document ).trigger( "ready" ).off( "ready" );
                }
            }
        },
        bindReady: function() {
            console.log(readyList)
            if ( readyList ) {
                return;
            }
            readyList = jQuery.Callbacks( "once memory" );
    // Catch cases where $(document).ready() is called after the
    // browser event has already occurred.
            if ( document.readyState === "complete" ) {
    // Handle it asynchronously to allow scripts the opportunity to delay ready
                return setTimeout( jQuery.ready, 1 );
            }
    // Mozilla, Opera and webkit nightlies currently support this event
            if ( document.addEventListener ) {
    // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
    // A fallback to window.onload, that will always work
                window.addEventListener( "load", jQuery.ready, false );
    // If IE event model is used
            } else if ( document.attachEvent ) {
    // ensure firing before onload,
    // maybe late but safe also for iframes
                document.attachEvent( "onreadystatechange", DOMContentLoaded );
    // A fallback to window.onload, that will always work
                window.attachEvent( "onload", jQuery.ready );
    // If IE and not a frame
    // continually check to see if the document is ready
                var toplevel = false;
                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}
                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                }
            }
        },
    // See test/unit/core.js for details concerning isFunction.
    // Since version 1.3, DOM methods and functions like alert
    // aren't supported. They return false on IE (#2968).
        isFunction: function( obj ) {
            return jQuery.type(obj) === "function";
        },
        isArray: Array.isArray || function( obj ) {
            return jQuery.type(obj) === "array";
        },
        isWindow: function( obj ) {
            return obj != null && obj == obj.window;
        },
        isNumeric: function( obj ) {
            return !isNaN( parseFloat(obj) ) && isFinite( obj );
        },
        type: function( obj ) {
            return obj == null ?
                    String( obj ) :
            class2type[ toString.call(obj) ] || "object";
        },
    //纯对象的判断
        isPlainObject: function( obj ) {
    // Must be an Object.
    // Because of IE, we also have to check the presence of the constructor property.
    // Make sure that DOM nodes and window objects don't pass through, as well
            if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
                return false;
            }
            try {
    // Not own constructor property must be Object
                if ( obj.constructor &&
                        !hasOwn.call(obj, "constructor") &&
                        !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
                    return false;
                }
            } catch ( e ) {
    // IE8,9 Will throw exceptions on certain host objects #9897
                return false;
            }
    // Own properties are enumerated firstly, so to speed up,
    // if last one is own, then all properties are own.
            var key;
            for ( key in obj ) {}
            return key === undefined || hasOwn.call( obj, key );
        },
        isEmptyObject: function( obj ) {
            for ( var name in obj ) {
    //如果有元素就说明不是空的对象
                return false;
            }
            return true;
        },
        error: function( msg ) {
            throw new Error( msg );
        },
        parseJSON: function( data ) {
    //字符串转化为json
            if ( typeof data !== "string" || !data ) {
                return null;
            }
    // Make sure leading/trailing whitespace is removed (IE can't handle it)
            data = jQuery.trim( data );
    // Attempt to parse using the native JSON parser first
            if ( window.JSON && window.JSON.parse ) {
                return window.JSON.parse( data );
            }
    // Make sure the incoming data is actual JSON
    // Logic borrowed from http://json.org/json2.js
            if ( rvalidchars.test( data.replace( rvalidescape, "@" )
                            .replace( rvalidtokens, "]" )
                            .replace( rvalidbraces, "")) ) {
                return ( new Function( "return " + data ) )();
            }
            jQuery.error( "Invalid JSON: " + data );
        },
    // Cross-browser xml parsing
        parseXML: function( data ) {
            if ( typeof data !== "string" || !data ) {
                return null;
            }
            var xml, tmp;
            try {
                if ( window.DOMParser ) { // Standard
                    tmp = new DOMParser();
                    xml = tmp.parseFromString( data , "text/xml" );
                } else { // IE
                    xml = new ActiveXObject( "Microsoft.XMLDOM" );
                    xml.async = "false";
                    xml.loadXML( data );
                }
            } catch( e ) {
                xml = undefined;
            }
            if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
                jQuery.error( "Invalid XML: " + data );
            }
            return xml;
        },
        noop: function() {},
    // Evaluates a script in a global context
    // Workarounds based on findings by Jim Driscoll
    // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
        globalEval: function( data ) {
            if ( data && rnotwhite.test( data ) ) {
    // We use execScript on Internet Explorer
    // We use an anonymous function so that context is window
    // rather than jQuery in Firefox
                ( window.execScript || function( data ) {
                    window[ "eval" ].call( window, data );
                } )( data );
            }
        },
    // Convert dashed to camelCase; used by the css and data modules
    // Microsoft forgot to hump their vendor prefix (#9572)
        camelCase: function( string ) {
            return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
        },
    //例如当string为“-ms-aaaa” 得到的是msAaa;
    //rmsPrefix = /^-ms-/,第一个replace结束后得到 ms-aaa
    //rdashAlpha = /-([a-z]|[0-9])/ig,第二个replace 匹配了-a fcamelCase(all,letter,index)
    //all为-a,letter为$1,为a,index=2 开始匹配的位置,从0开始
        nodeName: function( elem, name ) {
            return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
        },
    // args is for internal usage only
        each: function( object, callback, args ) {
            var name, i = 0,
    //有长度
                    length = object.length,
    //json对象的遍历
                    isObj = length === undefined || jQuery.isFunction( object );
    //args为真
            if ( args ) {
                if ( isObj ) {
                    for ( name in object ) {
    //举个例子:function add(b){console.log(b);}
    //$.each({'aaa':{ccc:1,'bbb':222}},add,['aaa']);
    //传递一个直接的参数,进行操作
                        if ( callback.apply( object[ name ], args ) === false ) {
                            break;
                        }
                    }
                } else {
                    for ( ; i < length; ) {
    //传递一个直接的参数,进行操作
                        if ( callback.apply( object[ i++ ], args ) === false ) {
                            break;
                        }
                    }
                }
    // A special, fast, case for the most common use of each
            } else {
                if ( isObj ) {
                    for ( name in object ) {
    //$.each([1,3,5,6],function(i,v){})
                        if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
                            break;
                        }
                    }
                } else {
                    for ( ; i < length; ) {
                        if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
                            break;
                        }
                    }
                }
            }
            return object;
        },
    // Use native String.trim function wherever possible
        trim: trim ?
                function( text ) {
                    return text == null ?
                            "" :
                            trim.call( text );
                } :
    // Otherwise use our own trimming functionality
                function( text ) {
                    return text == null ?
                            "" :
                            text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
                },
    // results is for internal usage only
        makeArray: function( array, results ) {
            var ret = results || [];
            if ( array != null ) {
    // The window, strings (and functions) also have 'length'
    // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
                var type = jQuery.type( array );
                if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
                    push.call( ret, array );
                } else {
                    jQuery.merge( ret, array );
                }
            }
            return ret;
        },
        inArray: function( elem, array, i ) {
            var len;
            if ( array ) {
                if ( indexOf ) {
                    return indexOf.call( array, elem, i );
                }
    //首先执行 i < 0 ? Math.max( 0, len + i ) : i
    //如果不存在就从0开始,否则从当i<0时,len+i开始,>0直接从开始
                len = array.length;
                i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
                for ( ; i < len; i++ ) {
    //返回所在位置
                    if ( i in array && array[ i ] === elem ) {
                        return i;
                    }
                }
            }
            return -1;
        },
        merge: function( first, second ) {
    //jQuery.merge( ret, array );
    //传入的是init,和一个array
            console.log(first);
            console.log(second)
            var i = first.length,
                    j = 0;
    //如果array是一个数组,在init的基础上再增加输入
            if ( typeof second.length === "number" ) {
                for ( var l = second.length; j < l; j++ ) {
                    first[ i++ ] = second[ j ];
                }
            } else {
                while ( second[j] !== undefined ) {
                    first[ i++ ] = second[ j++ ];
                }
            }
            first.length = i;
    //得到数组
            return first;
        },
        grep: function( elems, callback, inv ) {
    //grep() 方法是按照某种条件来过滤数组
            var ret = [], retVal;
            inv = !!inv;
    // Go through the array, only saving the items
    // that pass the validator function
    //举个例子 var ccc=$.grep([1,2,4,'bb','cc'],function(v,i){return $.type(v)=='number'})
    //console.log(ccc);[1, 2, 4]
    //当最后参数设置为true是,到得到['bb','cc']
            for ( var i = 0, length = elems.length; i < length; i++ ) {
                retVal = !!callback( elems[ i ], i );
                if ( inv !== retVal ) {
                    ret.push( elems[ i ] );
                }
            }
            return ret;
        },
    // arg is for internal usage only
        map: function( elems, callback, arg ) {
            var value, key, ret = [],
                    i = 0,
                    length = elems.length,
    // jquery objects are treated as arrays
    //jquery对象也被当做是数组,如$('div')
                    isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
    // 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 ( key in elems ) {
                    value = callback( elems[ key ], key, arg );
                    if ( value != null ) {
                        ret[ ret.length ] = value;
                    }
                }
            }
    // Flatten any nested arrays
            return ret.concat.apply( [], ret );
        },
    // A global GUID counter for objects
        guid: 1,
    // Bind a function to a context, optionally partially applying any
    // arguments.
        proxy: function( fn, context ) {
            if ( typeof context === "string" ) {
                var tmp = fn[ context ];
                context = fn;
                fn = tmp;
            }
    // Quick check to determine if target is callable, in the spec
    // this throws a TypeError, but we will just return undefined.
            if ( !jQuery.isFunction( fn ) ) {
                return undefined;
            }
    // Simulated bind
            var args = slice.call( arguments, 2 ),
                    proxy = function() {
                        return fn.apply( context, args.concat( slice.call( arguments ) ) );
                    };
    // Set the guid of unique handler to the same of original handler, so it can be removed
            proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
            return proxy;
        },
    // Mutifunctional method to get and set values to a collection
    // The value/s can optionally be executed if it's a function
        access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
            var exec,
                    bulk = key == null,
                    i = 0,
                    length = elems.length;
    // Sets many values
            if ( key && typeof key === "object" ) {
                for ( i in key ) {
                    jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
                }
                chainable = 1;
    // Sets one value
            } else if ( value !== undefined ) {
    // Optionally, function values get executed if exec is true
                exec = pass === undefined && jQuery.isFunction( value );
                if ( bulk ) {
    // Bulk operations only iterate when executing function values
                    if ( exec ) {
                        exec = fn;
                        fn = function( elem, key, value ) {
                            return exec.call( jQuery( elem ), value );
                        };
    // Otherwise they run against the entire set
                    } else {
                        fn.call( elems, value );
                        fn = null;
                    }
                }
                if ( fn ) {
                    for (; i < length; i++ ) {
                        fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
                    }
                }
                chainable = 1;
            }
            return chainable ?
                    elems :
    // Gets
                    bulk ?
                            fn.call( elems ) :
                            length ? fn( elems[0], key ) : emptyGet;
        },
        now: function() {
    //返回当前的时间
            return ( new Date() ).getTime();
        },
    // Use of jQuery.browser is frowned upon.
    // More details: http://docs.jquery.com/Utilities/jQuery.browser
        uaMatch: function( ua ) {
            ua = ua.toLowerCase();
            var match = rwebkit.exec( ua ) ||
                    ropera.exec( ua ) ||
                    rmsie.exec( ua ) ||
                    ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
                    [];
            return { browser: match[1] || "", version: match[2] || "0" };
        },
        sub: function() {
            function jQuerySub( selector, context ) {
                return new jQuerySub.fn.init( selector, context );
            }
            jQuery.extend( true, jQuerySub, this );
            jQuerySub.superclass = this;
            jQuerySub.fn = jQuerySub.prototype = this();
            jQuerySub.fn.constructor = jQuerySub;
            jQuerySub.sub = this.sub;
            jQuerySub.fn.init = function init( selector, context ) {
                if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
                    context = jQuerySub( context );
                }
                return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
            };
            jQuerySub.fn.init.prototype = jQuerySub.fn;
            var rootjQuerySub = jQuerySub(document);
            return jQuerySub;
        },
        browser: {}
    });
    // Populate the class2type map
    jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
        class2type[ "[object " + name + "]" ] = name.toLowerCase()
    });
    browserMatch = jQuery.uaMatch( userAgent );
    if ( browserMatch.browser ) {
        jQuery.browser[ browserMatch.browser ] = true;
        jQuery.browser.version = browserMatch.version;
    }
    // Deprecated, use jQuery.browser.webkit instead
    if ( jQuery.browser.webkit ) {
        jQuery.browser.safari = true;
    }
  • 相关阅读:
    DRF项目之视图获取路径参数
    DRF项目之层级关系
    DRF项目之序列化器和视图重写方法的区别
    DRF项目之自定义分页器
    DRF项目之实现用户密码加密保存
    DRF项目之通过业务逻辑选择数据集和序列化器
    DRF项目之自定义JWT认证响应数据
    PIP一次性导入所有环境和指定镜像源
    DRF项目之JWT认证方式的简介及使用
    DRF项目之解决浏览器同源策略问题
  • 原文地址:https://www.cnblogs.com/heyinwangchuan/p/6253773.html
Copyright © 2011-2022 走看看