来吧, 慢慢折腾吧

总结一下:

  jq1.4挺简单的, 正则写的不多, 看的都懂, 多写一些

  三目写法到底要不要

  特殊的地方的注释一定要有

  

/*!
 * jQuery JavaScript Library v1.4
 * http://jquery.com/
 *
 * Copyright 2010, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://docs.jquery.com/License
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 * Copyright 2010, The Dojo Foundation
 * Released under the MIT, BSD, and GPL Licenses.
 * 先读1.4的源代码吧, 也可以看看JS这几年的变化,有空去看prototype;
 * Date: Wed Jan 13 15:23:05 2010 -0500
 * jQ中正则的资料 : http://www.jmrware.com/articles/2010/jqueryregex/jQueryRegexes.html
 * 工具方法;
 * 浏览器判断;
 * 浏览器支持;
 * 数据缓存, 数据队列;
 * class操作;
 * 事件系统;
 * sizzle;
 * 元素选择的操作(节点过滤,节点周围元素选择);
 * DOM节点的操作和DOM节点之间的相互操作;
 */
(function( window, undefined ) {

// Define a local copy of jQuery
    var jQuery = function( selector, context ) {
            // The jQuery object is actually just the init constructor 'enhanced'
            return new jQuery.fn.init( selector, context );
        },

    //保存原来window.jQuery和window.$的数据,避免被重写;
    // Map over jQuery in case of overwrite
        _jQuery = window.jQuery,

    // Map over the $ in case of overwrite
        _$ = window.$,
    /*
     * 1.传入window
     * 通过传入window变量,使得window由全局变量变为局部变量
     * 当在jQuery代码块中访问window时,不需要将作用域链回退到顶层作用域,这样可以更快的访问window
     * 更重要的是,将window作为参数传入,可以在压缩代码时进行优化
     * (function(a,b){})(window);window 被优化为 a,压缩后文件更小
     * 2.传入undefined
     * 是为了在"自调用匿名函数"的作用域内,确信undefined是真的未定义
     * 因为undefined能够被重写,赋予新的值 
     * undefined = "now it's defined";
     * alert( undefined );
     * 浏览器测试结果:
     * ------------+----------------------+-------------
     *   浏览器       |    测试结果          |   结论
     *   ie           |    now it's defined  |   可以改变
     *   firefox   |    undefined          |   不能改变
     *   chrome       |    now it's defined  |   可以改变
     *   opera       |    now it's defined  |   可以改变
     * ------------+----------------------+-------------
     */
    //所有的API东西都是在window下的,直接从window下获取,提高查询的效率;
    // Use the correct document accordingly with window argument (sandbox)
        document = window.document,

    // A central reference to the root jQuery(document)
        rootjQuery,

    // A simple way to check for HTML strings or ID strings
    // (both of which we optimize for)
    // ^[^<]匹配非<开头 
    // (<[\w\W]+>) 匹配闭合的标签;
    // [^>]* 非右尖括号的字符,
    // 或者#([\w-]+)匹配ID;
        quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,

    // Is it a simple selector
    //匹配开头是.的字符串, 这个就是匹配class;
        isSimple = /^.[^:#\[\.,]*$/,

    /*
     *匹配非空白字符,匹配[^ \f\n\r\t\v];
     *" "\f换页附 \n换行 \r回车 \t制表符 \v垂直制表符;
     */
    // Check if a string has a non-whitespace character in it
        rnotwhite = /\S/,

    // Used for trimming whitespace
    //匹配开头或者结尾的空格; \u00A0是全角的空格;
        rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,

    // Match a standalone tag
    // 匹配闭合标签或者是单个标签
    // ^<(\w+)\s*\/?> 开头是<,(\w)+至少一个字符串,\s*有或者没有空格,> 闭合标签
    // ?:<\/\1>? 可以匹配到或者匹配不到都行
        rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,

    // Keep a UserAgent string for use with jQuery.browser
        userAgent = navigator.userAgent,

    // For matching the engine and version of the browser
        browserMatch,

    //文档是否加载完毕的标识符;
    // Has the ready events already been bound?
        readyBound = false,

    //DOM加载完毕的执行的函数列表;
    // The functions to execute on DOM ready
        readyList = [],

    //这个闭包内的全局变量;
    // The ready event handler
        DOMContentLoaded,

    // Save a reference to some core methods
    //简写, 这样就不用写一大串东东了;
        toString = Object.prototype.toString,
        hasOwnProperty = Object.prototype.hasOwnProperty,
        push = Array.prototype.push,
        slice = Array.prototype.slice,
        indexOf = Array.prototype.indexOf;

    jQuery.fn = jQuery.prototype = {
        //在高版本有个constructor指向Query自己;
        //这个constructor为Object;

        //jQ1.8的第三个参数为 rootjQuery;
        init: function( selector, context ) {
            var match, elem, ret, doc;

            // Handle $(""), $(null), or $(undefined)
            // or  $(false);
            if ( !selector ) {
                return this;
            }

            // Handle $(DOMElement)
            if ( selector.nodeType ) {
                this.context = this[0] = selector;
                this.length = 1;
                return this;
            }

            // Handle HTML strings
            if ( typeof selector === "string" ) {
                // Are we dealing with HTML string or an ID?
                // quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
                match = quickExpr.exec( selector );
                //debugger;
                //$("<div></div>") ==>> ["<div></div>", "<div></div>", undefined];
                //$("#div1") ==>> ["#div1", undefined, "div1"];
                // Verify a match, and that no context was specified for #id
                //匹配到东西  
                //match[1]有东西说明了是新建的匹配到了
                //没有上下文说明是匹配到ID的, 也会走进来;
                if ( match && (match[1] || !context) ) {

                    // HANDLE: $(html) -> $(array)
                    //新建元素;
                    if ( match[1] ) {
                        //指定文档,可能存在跨文档的情况;
                        doc = (context ? context.ownerDocument || context : document);

                        // If a single string is passed in and it's a single tag
                        // just do a createElement and skip the rest
                        ///^<(\w+)\s*\/?>(?:<\/\1>)?$/,
                        ret = rsingleTag.exec( selector );

                        if ( ret ) {
                            //$("<div>",{xx:1, yy:2});
                            if ( jQuery.isPlainObject( context ) ) {
                                selector = [ document.createElement( ret[1] ) ];
                                jQuery.fn.attr.call( selector, context, true );

                            } else {
                                //直接创建标签名;
                                selector = [ doc.createElement( ret[1] ) ];
                            }

                        } else {
                            //用匹配的内容生成元素;
                            ret = buildFragment( [ match[1] ], [ doc ] );

                            //对返回的数据进行处理;
                            selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
                        };

                        // HANDLE: $("#id")
                    } else {
                        //匹配到ID了;
                        elem = document.getElementById( match[2] );

                        if ( elem ) {
                            // Handle the case where IE and Opera return items
                            // by name instead of ID
                            //ie6,7的的name和id一样的话,而且name的元素在前面, 会找到name的节点;
                            if ( elem.id !== match[2] ) {
                                //用sizzle跑就不会出问题了;
                                return rootjQuery.find( selector );
                            }

                            // Otherwise, we inject the element directly into the jQuery object
                            this.length = 1;
                            this[0] = elem;
                        }

                        this.context = document;
                        this.selector = selector;
                        return this;
                    }

                    // HANDLE: $("TAG")
                    //匹配标签名, 上下问为document;
                } else if ( !context && /^\w+$/.test( selector ) ) {
                    this.selector = selector;
                    this.context = document;
                    selector = document.getElementsByTagName( selector );

                    // HANDLE: $(expr, $(...))
                } else if ( !context || context.jquery ) {
                    return (context || rootjQuery).find( selector );

                    // HANDLE: $(expr, context)
                    // (which is just equivalent to: $(context).find(expr)
                    //反正是把所有的情况匹配了个遍;
                } else {
                    return jQuery( context ).find( selector );
                }

                // HANDLE: $(function)
                // Shortcut for document ready
            } else if ( jQuery.isFunction( selector ) ) {
                return rootjQuery.ready( selector );
            }

            //统一处理,新建节点 等 没有返回的元素;
            if (selector.selector !== undefined) {
                this.selector = selector.selector;
                this.context = selector.context;
            };
            //$("<div>sdfsdf</div>") ==>> $("<div>sdfsdf</div>")
            //转化成jQ数组
            return jQuery.isArray( selector ) ?
                this.setArray( selector ) :
                jQuery.makeArray( selector, this );
        },

        // Start with an empty selector
        //这个selector是在原型上的;
        selector: "",

        // The current version of jQuery being used
        jquery: "1.4",

        //也是原型上的,会被重写的;
        // The default length of a jQuery object is 0
        length: 0,

        // The number of elements contained in the matched element set
        size: function() {
            return this.length;
        },

        //通过slice转化成纯数组;
        toArray: function() {
            return slice.call( this, 0 );
        },

        // Get the Nth element in the matched element set OR
        // Get the whole matched element set as a clean array
        get: function( num ) {
            return num == null ?

                // Return a 'clean' array
                this.toArray() :

                // Return just the object
                ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
        },

        // Take an array of elements and push it onto the stack
        // (returning the new matched element set)
        // $(el).pushStack("#idid")返回找到的元素,原来的el保存到prevObject里面了;
        pushStack: function( elems, name, selector ) {
            // Build a new jQuery matched element set
            var ret = jQuery( elems || null );
            //debugger;
            // Add the old object onto the stack (as a reference)
            ret.prevObject = this;

            ret.context = this.context;

            if ( name === "find" ) {
                ret.selector = this.selector + (this.selector ? " " : "") + selector;
            } else if ( name ) {
                //div.slice();
                //div.slice(0,4);
                ret.selector = this.selector + "." + name + "(" + selector + ")";
            }

            // Return the newly-formed element set
            return ret;
        },

        // Force the current matched set of elements to become
        // the specified array of elements (destroying the stack in the process)
        // You should use pushStack() in order to do this, but maintain the stack
        //强制设置当前对象的元素为elems;
        setArray: function( elems ) {
            // Resetting the length to 0, then using the native Array push
            // is a super-fast way to populate an object with array-like properties
            this.length = 0;
            push.apply( this, elems );

            return this;
        },

        // Execute a callback for every element in the matched set.
        // (You can seed the arguments with an array of args, but this is
        // only used internally.)
        //调用工具方法, 有第二个参数args;
        each: function( callback, args ) {
            return jQuery.each( this, callback, args );
        },

        ready: function( fn ) {
            // Attach the listeners
            jQuery.bindReady();

            // If the DOM is already ready
            if ( jQuery.isReady ) {
                // Execute the function immediately
                fn.call( document, jQuery );

                // Otherwise, remember the function for later
            } else if ( readyList ) {
                // Add the function to the wait list
                readyList.push( fn );
            }

            return this;
        },

        eq: function( i ) {
            return i === -1 ?
                this.slice( i ) :
                this.slice( i, +i + 1 );
        },

        first: function() {
            return this.eq( 0 );
        },

        last: function() {
            return this.eq( -1 );
        },

        slice: function() {
            //感觉pushStack的第三个参数没啥用;
            return this.pushStack( slice.apply( this, arguments ),
                "slice", slice.call(arguments).join(",") );
        },

        map: function( callback ) {
            //迭代this, 返回新的this;
            return this.pushStack( jQuery.map(this, function( elem, i ) {
                return callback.call( elem, i, elem );
            }));
        },

        end: function() {
            return this.prevObject || jQuery(null);
        },

        // For internal use only.
        // Behaves like an Array's method, not like a jQuery method.
        push: push,
        sort: [].sort,
        splice: [].splice
    };

// Give the init function the jQuery prototype for later instantiation
    jQuery.fn.init.prototype = jQuery.fn;

//jQuery中的继承的方法, 复制继承;
    jQuery.extend = jQuery.fn.extend = function() {
        // copy reference to target object
        var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;

        // Handle a deep copy situation
        if ( typeof target === "boolean" ) {
            deep = target;
            target = arguments[1] || {};
            // skip the boolean and the target
            i = 2;
        }

        // Handle case when target is a string or something (possible in deep copy)
        if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
            target = {};
        }

        // extend jQuery itself if only one argument is passed
        //如果是jQuery.extend就继承到jQuery上面去,
        //如果是jQuery.fn.extend就继承到jQuery.fn上面去;
        if ( length === i ) {
            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 object literal values or arrays
                    if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
                        var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
                            : jQuery.isArray(copy) ? [] : {};

                        // Never move original objects, clone them
                        target[ name ] = jQuery.extend( deep, clone, copy );

                        // Don't bring in undefined values
                        //基本的对象number, string, boolean就复制 , object就赋址;
                    } else if ( copy !== undefined ) {
                        target[ name ] = copy;
                    }
                }
            }
        }

        // Return the modified object
        return target;
    };

    jQuery.extend({
        //
        noConflict: function( deep ) {
            window.$ = _$;

            if ( deep ) {
                window.jQuery = _jQuery;
            }

            return jQuery;
        },

        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,


        //document绑定了事件, 如果到时间的话就会走ready;
        // Handle when the DOM is ready
        ready: function() {
            //没执行过的话
            // Make sure that the DOM is not already loaded
            if ( !jQuery.isReady ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                //如果在body还没加载完毕就执行$.ready()就延迟一点在执行这个函数;
                if ( !document.body ) {
                    return setTimeout( jQuery.ready, 13 );
                }

                // Remember that the DOM is ready
                jQuery.isReady = true;

                // If there are functions bound, to execute
                if ( readyList ) {
                    // Execute all of them
                    var fn, i = 0;
                    //逐个执行;
                    while ( (fn = readyList[ i++ ]) ) {
                        fn.call( document, jQuery );
                    }

                    // Reset the list of functions
                    readyList = null;
                }

                //可以为dom添加自定义事件;
                // Trigger any bound ready events
                if ( jQuery.fn.triggerHandler ) {
                    jQuery( document ).triggerHandler( "ready" );
                }
            }
        },

        bindReady: function() {
            if ( readyBound ) {
                return;
            }

            readyBound = true;

            // Catch cases where $(document).ready() is called after the
            // browser event has already occurred.
            //DOM的加载已经执行过一次了.
            if ( document.readyState === "complete" ) {
                return jQuery.ready();
            };

            //标准浏览器的事件绑定
            // 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
                //IE下的任何需要访问网络的元素都有onreadystatechange事件;
                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;
                //window.frameElement 是什么?
                //form http://blog.csdn.net/fudesign2008/article/details/6075055;
                //is the element which the window is embedded into, or  null   if the window is top-level.
                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}

                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                    //IE的hack, 成功了也会调用jQuery.ready;
                };

            }
        },

        // 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).
        //http://bugs.jquery.com/attachment/ticket/2968/2968.diff没懂,用qunit跑的;
        isFunction: function( obj ) {
            return toString.call(obj) === "[object Function]";
        },

        isArray: function( obj ) {
            return toString.call(obj) === "[object Array]";
        },

        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
            //这个是必须的                                        //节点属性         //window;
            if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
                return false;
            }

            // Not own constructor property must be Object
            //避免报错
            if ( obj.constructor
                //还要测试这个..
                && !hasOwnProperty.call(obj, "constructor")
                //和这个
                && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
                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 || hasOwnProperty.call( obj, key );
        },

        //纯空的对象;
        isEmptyObject: function( obj ) {
            for ( var name in obj ) {
                return false;
            }
            return true;
        },


        noop: function() {},


        // Evalulates a script in a global context
        globalEval: function( data ) {
            /*rnotwhite是什么;非纯空格的空格;
             *匹配非空白字符,匹配[^ \f\n\r\t\v];
             *" "\f换页附 \n换行 \r回车 \t制表符 \v垂直制表符;
             */
            // Check if a string has a non-whitespace character in it
            rnotwhite = /\S/;
            if ( data && rnotwhite.test(data) ) {
                // Inspired by code by Andrea Giammarchi
                // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
                var head = document.getElementsByTagName("head")[0] || document.documentElement,
                    script = document.createElement("script");
                script.type = "text/javascript";

                if ( jQuery.support.scriptEval ) {
                    script.appendChild( document.createTextNode( data ) );
                } else {
                    script.text = data;
                }

                // Use insertBefore instead of appendChild to circumvent an IE6 bug.
                // This arises when a base node is used (#2709).
                head.insertBefore( script, head.firstChild );
                head.removeChild( script );
            }
            /*
             TODO: 如果直接eval可行吗?
             (1,eval)(data)?
             */
        },

        //$.fn.nodeName = function() { $.nodeName.apply( elem,slice(arguments) ); };
        nodeName: function( elem, name ) {
            return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
        },

        //
        // args is for internal usage only
        ////$.fn.each = function(callback) { $.each( this.slice(),  callback) };
        each: function( object, callback, args ) {
            var name, i = 0,
                length = object.length,
                isObj = length === undefined || jQuery.isFunction(object);
            //args是提供内部使用的, 我想这东西哪里用到了;
            if ( args ) {
                if ( isObj ) {
                    for ( name in object ) {
                        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 ) {
                        if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
                            break;
                        }
                    }
                } else {
                    for ( var value = object[0];
                          i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
                }
            }

            return object;
        },

        trim: function( text ) {
            return (text || "").replace( rtrim, "" );
        },

        // results is for internal usage only
        /*
         $.makeArray({0:1,1:3,length:2})
         [1, 3]
         */
        makeArray: function( array, results ) {
            var ret = results || [];

            if ( array != null ) {
                // The window, strings (and functions) also have 'length'
                // The extra typeof function check is to prevent crashes
                // in Safari 2 (See: #3039)
                if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
                    push.call( ret, array );
                } else {
                    jQuery.merge( ret, array );
                }
            }

            return ret;
        },

        inArray: function( elem, array ) {
            //多数都有indexOf这方法;
            if ( array.indexOf ) {
                return array.indexOf( elem );
            }

            //可以遍历类数组;
            for ( var i = 0, length = array.length; i < length; i++ ) {
                if ( array[ i ] === elem ) {
                    return i;
                }
            }

            //跟默认的一样
            return -1;
        },

        //merge数组或对象到第一个参数, 我不会说这个东西跟extend差不多;
        merge: function( first, second ) {
            var i = first.length, j = 0;

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

            //修正length;
            first.length = i;

            return first;
        },

        //可以遍历类数组, 
        //inv 默认就是undefined
        grep: function( elems, callback, inv ) {
            var ret = [];

            // Go through the array, only saving the items
            // that pass the validator function
            for ( var i = 0, length = elems.length; i < length; i++ ) {
                //!inv === true; 如果callback返回true; 者ture !== ture为真;
                //元素, index; 顺序和原生的Array.filter一摸一样;
                if ( !inv !== !callback( elems[ i ], i ) ) {
                    ret.push( elems[ i ] );
                }
            }

            return ret;
        },

        // arg is for internal usage only
        map: function( elems, callback, arg ) {
            var ret = [], value;

            // Go through the array, translating each of the items to their
            // new value (or values).
            for ( var i = 0, length = elems.length; i < length; i++ ) {
                value = callback( elems[ i ], i, arg );
                // 不等于null 和 undefined;
                if ( value != null ) {
                    //相当于ret.push( value );
                    ret[ ret.length ] = value;
                }
            }
            //flaten, 扁平化;
            /*
             [].concat.apply([],[0,1,2,[3,4]])
             [0, 1, 2, 3, 4]
             */
            return ret.concat.apply( [], ret );
        },

        // A global GUID counter for objects
        guid: 1,
        //$.proxy( function(){console.log(this)}, document.body)()
        proxy: function( fn, proxy, thisObject ) {
            //修正参数;
            //如果参数只有两个;
            if ( arguments.length === 2 ) {
                //调用第一个对象的的方法;
                //$.proxy( { a : function(){console.log(this)}},"a" )()
                if ( typeof proxy === "string" ) {
                    thisObject = fn;
                    fn = thisObject[ proxy ];
                    proxy = undefined;

                    //proxy不是函数的话;
                    //$.proxy( function(){console.log(this)}, $)(); 意思就是如果你用$或者$.proxy作为上下文是不行的)——(函数怎么可能是上下文..
                } else if ( proxy && !jQuery.isFunction( proxy ) ) {
                    thisObject = proxy;
                    proxy = undefined;
                }
            };

            //没有proxy的话, 应该就只有fn了;
            if ( !proxy && fn ) {
                //直接用this作为这个context
                proxy = function() {
                    return fn.apply( thisObject || this, arguments );
                };
            }

            //proxy的第二个参数其实没啥用, 如果有传proxy就是把fn的guid给proxy的guid;
            //设置guid, 相当于一个标识;
            // Set the guid of unique handler to the same of original handler, so it can be removed
            if ( fn ) {
                proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
            }

            // So proxy can be declared as an argument
            return proxy;
        },

        // Use of jQuery.browser is frowned upon.
        // More details: http://docs.jquery.com/Utilities/jQuery.browser
        //line 840 把 userAgent传进来了;
        uaMatch: function( ua ) {
            var ret = { browser: "" };

            ua = ua.toLowerCase();

            if ( /webkit/.test( ua ) ) {
                ret = { browser: "webkit", version: /webkit[\/ ]([\w.]+)/ };

            } else if ( /opera/.test( ua ) ) {
                ret = { browser: "opera", version:  /version/.test( ua ) ? /version[\/ ]([\w.]+)/ : /opera[\/ ]([\w.]+)/ };

            } else if ( /msie/.test( ua ) ) {
                ret = { browser: "msie", version: /msie ([\w.]+)/ };

            } else if ( /mozilla/.test( ua ) && !/compatible/.test( ua ) ) {
                ret = { browser: "mozilla", version: /rv:([\w.]+)/ };
            }

            ret.version = (ret.version && ret.version.exec( ua ) || [0, "0"])[1];

            return ret;
        },

        browser: {}
    });

    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;
        //有必要加一个
        jQuery.browser.blink = true;
    }

//如果array的原型下有indexOf方法, 一般都有的;
    if ( indexOf ) {
        jQuery.inArray = function( elem, array ) {
            return indexOf.call( array, elem );
        };
    }

// All jQuery objects should point back to these
    rootjQuery = jQuery(document);

// Cleanup functions for the document ready method
//标准浏览器的方法
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            jQuery.ready();
        };

//IE下的绑定事件
    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                jQuery.ready();
            };
        };
    };

// The DOM ready check for Internet Explorer
//只是做IE的加载检测的hack;
    function doScrollCheck() {
        if ( jQuery.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch( error ) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        jQuery.ready();
    }

    if ( indexOf ) {
        jQuery.inArray = function( elem, array ) {
            return indexOf.call( array, elem );
        };
    };

//谁懂这个i是拿来干嘛用的
    function evalScript( i, elem ) {
        //如果是地址类型;
        if ( elem.src ) {
            jQuery.ajax({
                url: elem.src,
                async: false,
                dataType: "script"
            });
        } else {
            //如果这个是生成出来的标签, 把这个标签的内容eval出来;
            jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
        };

        if ( elem.parentNode ) {
            elem.parentNode.removeChild( elem );
        };
    };

//为了减少代码量, 用了一个access作为中间件;
// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
    function access( elems, key, value, exec, fn, pass ) {
        var length = elems.length;

        // Setting many attributes
        if ( typeof key === "object" ) {
            for ( var k in key ) {
                access( elems, k, key[k], exec, fn, value );
            }
            return elems;
        }

        // Setting one attribute
        if ( value !== undefined ) {
            // Optionally, function values get executed if exec is true
            exec = !pass && exec && jQuery.isFunction(value);

            for ( var i = 0; i < length; i++ ) {
                fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
            }

            return elems;
        }

        // Getting an attribute
        return length ? fn( elems[0], key ) : null;
    };

    function now() {
        return (new Date).getTime();
    };

    (function() {
        //处理浏览器兼容支持API
        jQuery.support = {};
        //根节点
        var root = document.documentElement,
        //这些节点只要创建一个, 减少内存占用, 提高性能;
            script = document.createElement("script"),
            div = document.createElement("div"),
            id = "script" + now();

        div.style.display = "none";
        div.innerHTML = "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

        var all = div.getElementsByTagName("*"),
            a = div.getElementsByTagName("a")[0];

        //连getElementByTagName都不好使了, 只能呵呵了;
        // Can't get basic test support
        if ( !all || !all.length || !a ) {
            return;
        };

        jQuery.support = {
            // IE strips leading whitespace when .innerHTML is used
            // IE会自动把innerHTML的头部和尾部空白清除, 标准浏览器全部忠于用户操作;
            leadingWhitespace: div.firstChild.nodeType === 3,

            /*
             var d = document.createElement("div");
             d.innerHTML = "<table></table>";
             var t = d.getElementsByTagName("table")[0];
             //==>> 标准浏览器的结果<table></table>;
             */
            // Make sure that tbody elements aren't automatically inserted
            // IE will insert them into empty tables
            tbody: !div.getElementsByTagName("tbody").length,

            //IE会自动补全的;
            // Make sure that link elements get serialized correctly by innerHTML
            // This requires a wrapper element in IE
            htmlSerialize: !!div.getElementsByTagName("link").length,

            //看看通过固有属性的方式能不能获取, 用的不多;
            // Get the style information from getAttribute
            // (IE uses .cssText insted)
            style: /red/.test( a.getAttribute("style") ),

            // Make sure that URLs aren't manipulated
            // (IE normalizes it by default)
            // IE会自动补全整个地址;
            hrefNormalized: a.getAttribute("href") === "/a",

            // Make sure that element opacity exists
            // (IE uses filter instead)
            // Use a regex to work around a WebKit issue. See #5145
            //在chrome的某些版本不能用opacity:.55;
            //http://bugs.jquery.com/ticket/5145
            opacity: /^0.55$/.test( a.style.opacity ),

            // Verify style float existence
            // (IE uses styleFloat instead of cssFloat)
            //styleFloat 和 cssFloat同意处理
            cssFloat: !!a.style.cssFloat,

            // Make sure that if no value is specified for a checkbox
            // that it defaults to "on".
            // (WebKit defaults to "" instead)
            checkOn: div.getElementsByTagName("input")[0].value === "on",

            // Make sure that a selected-by-default option has a working selected property.
            // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
            optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,

            // Will be defined later
            scriptEval: false,
            noCloneEvent: true,
            boxModel: null
        };

        script.type = "text/javascript";
        try {
            script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
        } catch(e) {}

        root.insertBefore( script, root.firstChild );

        // Make sure that the execution of code works by injecting a script
        // tag with appendChild/createTextNode
        // (IE doesn't support this, fails, and uses .text instead)
        if ( window[ id ] ) {
            //是否支持动态的添加script标签,内部的内容自动eval;
            jQuery.support.scriptEval = true;
            delete window[ id ];
        };

        root.removeChild( script );

        //IE下才有这种问题;
        //标准浏览器无路cloneNode还是cloneNode(true)都不会复制事件的;
        if ( div.attachEvent && div.fireEvent ) {
            div.attachEvent("onclick", function click() {
                // Cloning a node shouldn't copy over any
                // bound event handlers (IE does this)
                jQuery.support.noCloneEvent = false;
                div.detachEvent("onclick", click);
            });
            div.cloneNode(true).fireEvent("onclick");
        }

        // Figure out if the W3C box model works as expected
        // document.body must exist before we can do this
        // TODO: This timeout is temporary until I move ready into core.js.
        //这个东西要等到dom加载完毕以后才能测试的;
        jQuery(function() {
            var div = document.createElement("div");
            //quirk模式下的border-box模型的width包含了border和padding,导致这个元素的width为1;
            div.style.width = div.style.paddingLeft = "1px";

            document.body.appendChild( div );
            //如果等于2就是标准的盒模型content-box; 
            /*
             box-sizing的五种值:border-box;content-box;padding-box;initial;inherit;
             */
            jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
            document.body.removeChild( div ).style.display = 'none';
            div = null;
        });

        // Technique from Juriy Zaytsev
        // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
        var eventSupported = function( eventName ) {
            var el = document.createElement("div");
            eventName = "on" + eventName;

            //如果这个支持的话就不用走了;
            var isSupported = (eventName in el);
            if ( !isSupported ) {
                //使用固有属性的方法添加字符串"return;";
                el.setAttribute(eventName, "return;");
                isSupported = typeof el[eventName] === "function";
            }
            el = null;

            return isSupported;
        };

        jQuery.support.submitBubbles = eventSupported("submit");
        jQuery.support.changeBubbles = eventSupported("change");

        // release memory in IE
        root = script = div = all = a = null;
    })();

    jQuery.props = {
        "for": "htmlFor",
        "class": "className",
        readonly: "readOnly",
        maxlength: "maxLength",
        cellspacing: "cellSpacing",
        rowspan: "rowSpan",
        colspan: "colSpan",
        tabindex: "tabIndex",
        usemap: "useMap",
        frameborder: "frameBorder"
    };
//windowData是为了避免属性系统在window下新建变量, 导致全局污染
    var expando = "jQuery" + now(), uuid = 0, windowData = {};
    var emptyObject = {};

    jQuery.extend({
        cache: {},

        expando:expando,

        // The following elements throw uncatchable exceptions if you
        // attempt to add expando properties to them.
        noData: {
            "embed": true,
            "object": true,
            "applet": true
        },

        data: function( elem, name, data ) {
            if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
                return;
            }

            elem = elem == window ?
                windowData :
                elem;

            var id = elem[ expando ], cache = jQuery.cache, thisCache;

            // Handle the case where there's no name immediately
            if ( !name && !id ) {
                return null;
            }

            // Compute a unique ID for the element
            //如果没有id, 为元素分配一个id;
            if ( !id ) {
                id = ++uuid;
            }

            // Avoid generating a new cache unless none exists and we
            // want to manipulate it.
            // 如果是对象这个是覆盖重写缓存数据哦
            if ( typeof name === "object" ) {
                elem[ expando ] = id;
                thisCache = cache[ id ] = jQuery.extend(true, {}, name);
                //获取缓冲中的数据;
            } else if ( cache[ id ] ) {
                thisCache = cache[ id ];
            } else if ( typeof data === "undefined" ) {
                thisCache = emptyObject;
            } else {
                //新建一个数据吧;
                thisCache = cache[ id ] = {};
            }

            // Prevent overriding the named cache with undefined values
            if ( data !== undefined ) {
                elem[ expando ] = id;
                thisCache[ name ] = data;
            }

            //如果没有name就把整个缓冲返回回去;
            return typeof name === "string" ? thisCache[ name ] : thisCache;
        },

        removeData: function( elem, name ) {
            if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
                return;
            }

            elem = elem == window ?
                windowData :
                elem;
            //所有缓存的数据       //当前元素的数据
            var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];

            // If we want to remove a specific section of the element's data
            if ( name ) {
                if ( thisCache ) {
                    // Remove the section of cache data
                    delete thisCache[ name ];

                    // If we've removed all the data, remove the element's cache
                    if ( jQuery.isEmptyObject(thisCache) ) {
                        jQuery.removeData( elem );
                    }
                }

                // Otherwise, we want to remove all of the element's data
            } else {
                // Clean up the element expando
                //标准下真要删节点属性,IE反正两种都删了就好了呗
                try {
                    delete elem[ expando ];
                } catch( e ) {
                    // IE has trouble directly removing the expando
                    // but it's ok with using removeAttribute
                    if ( elem.removeAttribute ) {
                        elem.removeAttribute( expando );
                    }
                }

                // Completely remove the data cache
                delete cache[ id ];
            }
        }
    });

//原型下面方法的继承;
    jQuery.fn.extend({
        data: function( key, value ) {

            if ( typeof key === "undefined" && this.length ) {
                return jQuery.data( this[0] );

            } else if ( typeof key === "object" ) {
                //设置对象;
                //如果key是对象会把这个对象覆些这个元素的cache;
                return this.each(function() {
                    jQuery.data( this, key );
                });
            }
            //如果key是字符串的话;
            var parts = key.split(".");
            parts[1] = parts[1] ? "." + parts[1] : "";

            //这个地方何必使用到事件呢;
            if ( value === undefined ) {
                var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

                if ( data === undefined && this.length ) {
                    data = jQuery.data( this[0], key );
                }
                return data === undefined && parts[1] ?
                    this.data( parts[0] ) :
                    data;
            } else {
                return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
                    jQuery.data( this, key, value );
                });
            }
        },

        removeData: function( key ) {
            return this.each(function() {
                jQuery.removeData( this, key );
            });
        }
    });

//工具上面的queue和dequeue;
    /*
     $.queue(document.body,"","2");
     ["2"];
     */
    jQuery.extend({
        queue: function( elem, type, data ) {
            if ( !elem ) {
                return;
            };

            type = (type || "fx") + "queue";
            var q = jQuery.data( elem, type );

            // Speed up dequeue by getting out quickly if this is just a lookup
            if ( !data ) {
                return q || [];
            }
            //把这些数据弄成数组放进去,(这个应该是覆盖啊);
            if ( !q || jQuery.isArray(data) ) {
                q = jQuery.data( elem, type, jQuery.makeArray(data) );

            } else {
                q.push( data );
            }

            return q;
        },

        dequeue: function( elem, type ) {
            type = type || "fx";
            var queue = jQuery.queue( elem, type ), fn = queue.shift();

            //获取的第一个是 "inprogress"的话;
            // If the fx queue is dequeued, always remove the progress sentinel
            if ( fn === "inprogress" ) {
                //这盘肯定是函数了;
                fn = queue.shift();
            };

            //
            if ( fn ) {
                // Add a progress sentinel to prevent the fx queue from being
                // automatically dequeued
                //再把这个字符串压进去;
                if ( type === "fx" ) {
                    queue.unshift("inprogress");
                };

                //把这个函数执行, 执行有一个参数, 这个参数是下一个fx函数, 执行后就继续出列;
                fn.call(elem, function() {
                    jQuery.dequeue(elem, type);
                });
            }
        }
    });
    /*
     queue和 dequeue的使用方法;
     $("body").queue(function() {
     console.log(0);
     }).queue(function(next) {
     console.log(1);next();
     }).queue(function(next) {
     console.log(2);next();
     }).queue(function(next) {
     console.log(3);next()
     }).queue(function() {
     console.log(4);
     });

     $("body").dequeue();
     1;
     2;
     3;
     4;
     */
    jQuery.fn.extend({

        queue: function( type, data ) {
            if ( typeof type !== "string" ) {
                data = type;
                type = "fx";
            };

            //如果没有type和data就返回第一个;
            if ( data === undefined ) {
                return jQuery.queue( this[0], type );
            };

            //为各个元素添加key为type的 data数据;
            return this.each(function( i, elem ) {
                var queue = jQuery.queue( this, type, data );

                //默认就为fx; 
                //如果第一次执行那么queue[0]就是添加的数据,  就马上执行;
                if ( type === "fx" && queue[0] !== "inprogress" ) {
                    jQuery.dequeue( this, type );
                };
            });
        },

        //迭代每一个this, 然后把type + "queue"的缓存对象拉出来执行;
        dequeue: function( type ) {
            return this.each(function() {
                jQuery.dequeue( this, type );
            });
        },

        // Based off of the plugin by Clint Helfers, with permission.
        // http://blindsignals.com/index.php/2009/07/jquery-delay/
        delay: function( time, type ) {
            time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
            type = type || "fx";
            //其实和就是调用queue, 只是延迟了几秒钟;
            return this.queue( type, function() {
                var elem = this;
                setTimeout(function() {
                    jQuery.dequeue( elem, type );
                }, time );
            });
        },

        clearQueue: function( type ) {
            return this.queue( type || "fx", [] );
        }
    });

    var rclass = /[\n\t]/g,
        rspace = /\s+/,
        rreturn = /\r/g,
        rspecialurl = /href|src|style/,
        rtype = /(button|input)/i,
        rfocusable = /(button|input|object|select|textarea)/i,
        rclickable = /^(a|area)$/i,
        rradiocheck = /radio|checkbox/;

    jQuery.fn.extend({
        attr: function( name, value ) {
            return access( this, name, value, true, jQuery.attr );
        },

        removeAttr: function( name, fn ) {
            return this.each(function(){
                //也是调用原型的attr方法, 只不过值是空的;
                jQuery.attr( this, name, "" );
                if ( this.nodeType === 1 ) {
                    this.removeAttribute( name );
                }
            });
        },

        addClass: function( value ) {
            //是函数就特殊处理;
            if ( jQuery.isFunction(value) ) {
                return this.each(function(i) {
                    var self = jQuery(this);
                    self.addClass( value.call(this, i, self.attr("class")) );
                });
            };

            //jQ中的class增加的方法
            if ( value && typeof value === "string" ) {
                var classNames = (value || "").split( rspace );

                for ( var i = 0, l = this.length; i < l; i++ ) {
                    var elem = this[i];

                    if ( elem.nodeType === 1 ) {
                        if ( !elem.className ) {
                            elem.className = value;

                        } else {
                            var className = " " + elem.className + " ";
                            for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
                                if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
                                    elem.className += " " + classNames[c];
                                }
                            }
                        }
                    }
                }
            }

            return this;
        },

        //jQ重的class删除方法;
        removeClass: function( value ) {
            if ( jQuery.isFunction(value) ) {
                return this.each(function(i) {
                    var self = jQuery(this);
                    self.removeClass( value.call(this, i, self.attr("class")) );
                });
            }

            if ( (value && typeof value === "string") || value === undefined ) {
                var classNames = (value || "").split(rspace);

                for ( var i = 0, l = this.length; i < l; i++ ) {
                    var elem = this[i];

                    if ( elem.nodeType === 1 && elem.className ) {
                        if ( value ) {
                            var className = (" " + elem.className + " ").replace(rclass, " ");
                            for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
                                className = className.replace(" " + classNames[c] + " ", " ");
                            }
                            elem.className = className.substring(1, className.length - 1);

                        } else {
                            elem.className = "";
                        }
                    }
                }
            }

            return this;
        },

        toggleClass: function( value, stateVal ) {
            var type = typeof value, isBool = typeof stateVal === "boolean";

            if ( jQuery.isFunction( value ) ) {
                return this.each(function(i) {
                    var self = jQuery(this);
                    self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
                });
            }

            return this.each(function() {
                if ( type === "string" ) {
                    // toggle individual class names
                    //转成jQ对象;
                    var className, i = 0, self = jQuery(this),
                        state = stateVal,
                        classNames = value.split( rspace );
                    //第一次还是第0个class的;
                    while ( (className = classNames[ i++ ]) ) {
                        // check each className given, space seperated list
                        state = isBool ? state : !self.hasClass( className );
                        self[ state ? "addClass" : "removeClass" ]( className );
                    }
                } else if ( type === "undefined" || type === "boolean" ) {
                    //把当前的class保存起来;
                    if ( this.className ) {
                        // store className if set
                        jQuery.data( this, "__className__", this.className );
                    };

                    //$(xx).toggle(false)
                    //$(xx).toggle() 这两种调用方法;
                    //反正是设置;
                    // toggle whole className;
                    this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
                }
            });
        },

        hasClass: function( selector ) {
            var className = " " + selector + " ";
            for ( var i = 0, l = this.length; i < l; i++ ) {
                if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
                    return true;
                }
            }

            return false;
        },

        val: function( value ) {
            //获取值就获取一个;
            if ( value === undefined ) {
                var elem = this[0];

                if ( elem ) {
                    //如果是select下的option;
                    if ( jQuery.nodeName( elem, "option" ) ) {
                        //option.attributes.value && option.attributes.value.specified(指定); 如果这个元素的value有的话;
                        return (elem.attributes.value || {}).specified ? elem.value : elem.text;
                    };

                    // We need to handle select boxes special
                    if ( jQuery.nodeName( elem, "select" ) ) {
                        var index = elem.selectedIndex,
                            values = [],
                            options = elem.options,
                            one = elem.type === "select-one";

                        // Nothing was selected
                        if ( index < 0 ) {
                            return null;
                        }

                        // Loop through all the selected options
                        // 循环所有的option
                        for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
                            var option = options[ i ];

                            if ( option.selected ) {
                                // Get the specifc value for the option
                                value = jQuery(option).val();

                                // We don't need an array for one selects
                                if ( one ) {
                                    return value;
                                };

                                // Multi-Selects return an array
                                values.push( value );
                            };
                        };

                        //是mutipul的的话;
                        return values;
                    }

                    // chrome浏览器的问题;
                    // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
                    if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
                        return elem.getAttribute("value") === null ? "on" : elem.value;
                    }

                    //默认的, 有value的元素只有 select, checkbox, radio 这三个元素了;
                    // Everything else, we just grab the value
                    return (elem.value || "").replace(rreturn, "");

                }

                return undefined;
            };

            var isFunction = jQuery.isFunction(value);

            //设置值是设置所有的值;
            return this.each(function(i) {
                var self = jQuery(this), val = value;

                if ( this.nodeType !== 1 ) {
                    return;
                };

                //如果传进来的值, 重新计算需要的值, 参数为这个对象和这个对象的值;
                if ( isFunction ) {
                    val = value.call(this, i, self.val());
                };

                // Typecast each time if the value is a Function and the appended
                // value is therefore different each time.
                if ( typeof val === "number" ) {
                    val += "";
                };

                //你可以传一个数组, 如果这个raido的值有在这个数组里, 元素就设置checked = ture;
                //radio的值应该就一个的                //如果是radio元素;
                if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
                    //args(xx in the yy)
                    this.checked = jQuery.inArray( self.val(), val ) >= 0;
                    //PS : $("<input type='radio' id='r'/>").appendTo($("body"))[0].checked; 默认都为false, 好像webkit的某些版本为"on"
                } else if ( jQuery.nodeName( this, "select" ) ) {
                    //把values变成一个数组;
                    var values = jQuery.makeArray(val);

                    //所有对应的变成选中;
                    jQuery( "option", this ).each(function() {
                        this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
                    });

                    if ( !values.length ) {
                        this.selectedIndex = -1;
                    };

                } else {
                    this.value = val;
                };
            });
        }
    });

//整个的接口
    jQuery.extend({
        attrFn: {
            val: true,
            css: true,
            html: true,
            text: true,
            data: true,
            width: true,
            height: true,
            offset: true
        },

        attr: function( elem, name, value, pass ) {
            // don't set attributes on text and comment nodes
            //text文本;             //comment注释;
            if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
                return undefined;
            };

            //如果这个name在attrFn中存在, 就把这个值传进去,快捷设置;
            if ( pass && name in jQuery.attrFn ) {
                return jQuery(elem)[name](value);
            };

            //NODE                 //是XML取反;
            var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
            // Whether we are setting (or getting)
                set = value !== undefined;
            /*
             jQuery.props的属性修复方法: 
             这个存在的意义是因为有一些属性是保留字;
             有一些是因为HTML不区分大小写,但是JS区分大小写的缘故;
             {
             cellspacing: "cellSpacing",
             class: "className",
             colspan: "colSpan",
             for: "htmlFor",
             frameborder: "frameBorder",
             maxlength: "maxLength",
             readonly: "readOnly",
             rowspan: "rowSpan",
             tabindex: "tabIndex",
             usemap: "useMap
             }
             */
            // Try to normalize/fix the name
            name = notxml && jQuery.props[ name ] || name;

            // Only do all the following if this is a node (faster for style)
            if ( elem.nodeType === 1 ) {
                // These attributes require special treatment
                //  rspecialurl ==>> /href|src|style/;
                var special = rspecialurl.test( name );

                //修复safari的bug;
                // Safari mis-reports the default selected property of an option
                // Accessing the parent's selectedIndex property fixes it
                if ( name === "selected" && !jQuery.support.optSelected ) {
                    var parent = elem.parentNode;
                    if ( parent ) {
                        parent.selectedIndex;

                        // Make sure that it also works with optgroups, see #5701
                        if ( parent.parentNode ) {
                            parent.parentNode.selectedIndex;
                        }
                    }
                }

                // If applicable, access the attribute via the DOM 0 way
                if ( name in elem && notxml && !special ) {
                    //设置;
                    if ( set ) {
                        //    /(button|input)/i IE下的button和input的type不能随便更改; 就跟iframe的name和input的name不能随便更改一样;
                        //  We can't allow the type property to be changed (since it causes problems in IE)
                        if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
                            throw "type property can't be changed";
                        }
                        //如果 name in elem说明这个name是 id title className href src这些固有属性和文本属性都有的东西;
                        elem[ name ] = value;
                    };

                    //获取, 处理form的节点的值;
                    // browsers index elements by id/name on forms, give priority to attributes.
                    if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
                        return elem.getAttributeNode( name ).nodeValue;
                    };


                    // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
                    // 死链;
                    // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 
                    // 看看司徒正美的 :http://www.cnblogs.com/rubylouvre/archive/2009/12/07/1618182.html
                    /*
                     知识普及 : tabIndex在浏览器下都支持, tabIndex在W3C是属于节点属性又属于固有属性, 表单元素用的最多, 
                     //DIV等这些块节点在W3C下不能设置tabIndex, 但是所有浏览器厂商都实现了DIV的tabIndex;tabIndex如果有设置值得情况下,无论是通过固有属性还是节点方式获取,
                     值都能获取到,如下 :
                     <div tabindex="2">第二个</div>
                     $("div[tabindex=2]")[0].tabIndex  ==>> 2
                     $("div[tabindex=2]")[0].getAttribute("tabIndex") ==>> "2"
                     //这东西记也感觉记不住;
                     但是没有默认值得情况下, 标准浏览器通过节点属性 获取的值如果是DIV等元素 ==>> -1; 被设置了返回被设置的值; 是input这些元素 ==>> 0
                     如果是input这些元素 通过attribute获取 ==>> null;
                     IE67无论任何方式获取的都是返回0
                     //IE下判断这属性是否被设置;
                     var _hasAttr = function(node, name){
                     var attr = node.getAttributeNode && node.getAttributeNode(name);
                     return attr && attr.specified; // Boolean
                     };
                     */
                    if ( name === "tabIndex" ) {
                        var attributeNode = elem.getAttributeNode( "tabIndex" );

                        return attributeNode && attributeNode.specified ?
                            attributeNode.value :
                            rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
                                null :
                                undefined;
                    };

                    return elem[ name ];
                };

                //是固有属性了么么哒;
                if ( !jQuery.support.style && notxml && name === "style" ) {
                    if ( set ) {
                        elem.style.cssText = "" + value;
                    }

                    return elem.style.cssText;
                };

                //统一处理
                if ( set ) {
                    // convert the value to a string (all browsers do this but IE) see #1070
                    elem.setAttribute( name, "" + value );
                };

                //如果是href, src这些链接地址, 统一返回没有改变过的地址;
                var attr = !jQuery.support.hrefNormalized && notxml && special ?
                    // Some attributes require a special call on IE
                    elem.getAttribute( name, 2 ) :
                    elem.getAttribute( name );

                // Non-existent attributes return null, we normalize to undefined
                return attr === null ? undefined : attr;
            }

            // elem is actually elem.style ... set the style
            // Using attr for specific style information is now deprecated. Use style insead.
            return jQuery.style( elem, name, value );
        }
    });

// \ddfsdfsdf\w\s\. fsdfsdf\dfhfgh\ryr\werew  c  vx\\\\c/\v 
// ==>> "ddfsdfsdfws. fsdfsdfdfhfghyrwerew  c  vx\\\\c\/"

    var fcleanup = function( nm ) {
        //着我靠,匹配出来的是3个斜杠;
        return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
            return "\\" + ch;
        });
    };

    /*
     * A number of helper functions used for managing events.
     * Many of the ideas behind this code originated from
     * Dean Edwards' addEvent library.
     */
    jQuery.event = {

        // Bind an event to an element
        // Original by Dean Edwards
        // http://dean.edwards.name/
        add: function( elem, types, handler, data ) {
            //text和 comment元素混进来了;
            if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
                return;
            }

            // For whatever reason, IE has trouble passing the window object
            // around, causing it to be cloned in the process
            if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
                elem = window;
            };

            //无论如何都会设置唯一guid了, 方便进行函数的检索和接触绑定;
            // Make sure that the function being executed has a unique ID
            if ( !handler.guid ) {
                handler.guid = jQuery.guid++;
            };

            // if data is passed, bind to handler
            if ( data !== undefined ) {
                // Create temporary function pointer to original handler
                var fn = handler;

                // Create unique handler function, wrapped around original handler
                handler = jQuery.proxy( fn );

                // Store data in unique handler
                handler.data = data;
            };

            // Init the element's event structure
            var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
                handle = jQuery.data( elem, "handle" ), eventHandle;

            if ( !handle ) {
                eventHandle = function() {
                    // Handle the second event of a trigger and when
                    // an event is called after a page has unloaded
                    //这个应该不会错误的jQuery !== "undefined", 怎么可能呢?
                    //jQuery.event.triggered默认为false;
                    return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
                        //eventHandle为明确this指向, 所有的事件都是绑定同一个函数的;
                        jQuery.event.handle.apply( eventHandle.elem, arguments ) :
                        undefined;
                };

                //把这个组要handle绑定到缓存对象的handle;
                //而且jQ.data的返回就是指向缓存的指针, so the handle just equels eventHandle;
                handle = jQuery.data( elem, "handle", eventHandle );
            };

            // If no handle is found then we must be trying to bind to one of the
            // banned noData elements
            if ( !handle ) {
                return;
            };

            // Add elem as a property of the handle function
            // This is to prevent a memory leak with non-native
            // event in IE.
            handle.elem = elem;

            // Handle multiple events separated by a space
            // jQuery(...).bind("mouseover mouseout", fn);
            //处理传入的多种事件通过空格分隔的情况;
            types = types.split( /\s+/ );
            var type, i=0;
            while ( (type = types[ i++ ]) ) {
                // Namespaced event handlers
                // "click.xx.yy.zz" 命名空间的作用;
                var namespaces = type.split(".");
                type = namespaces.shift();
                //把命名空间放到 函数下面;
                handler.type = namespaces.slice(0).sort().join(".");

                //获取事件列表;
                /*
                 special ==>>
                 ready            function    function            
                 live            function    function    Object
                 beforeunload    function    function            
                 mouseenter        function    function            
                 mouseleave        function    function            
                 focusin            function    function            
                 focusout        function    function            
                 //基本都有四个方法;
                 setup
                 teardown
                 add
                 remove
                 */
                // Get the current list of functions bound to this event
                var handlers = events[ type ],
                    special = this.special[ type ] || {};



                // Init the event handler queue
                if ( !handlers ) {
                    //首先初始化事件列表, 对每一种类型的事件都要绑定同一个的handle;
                    handlers = events[ type ] = {};

                    // Check for a special event handler
                    // Only use addEventListener/attachEvent if the special
                    // events handler returns false
                    //如果pecial.setup为true, 就会跑后面的结果;
                    //像在chrome中不支持mouseenter的话就会用mouseover模拟mouseenter,
                    //重新绑定一次事件, 返回为false;
                    if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
                        //统一绑定 handle;
                        // Bind the global event handler to the element
                        if ( elem.addEventListener ) {
                            elem.addEventListener( type, handle, false );
                        } else if ( elem.attachEvent ) {
                            elem.attachEvent( "on" + type, handle );
                        }
                    }
                }

                //只有spcial的live中有add方法, 又是fix什么东西的额;
                if ( special.add ) {
                    var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
                    if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
                        modifiedHandler.guid = modifiedHandler.guid || handler.guid;
                        handler = modifiedHandler;
                    }
                }

                //事件用guid进行
                // Add the function to the element's handler list
                handlers[ handler.guid ] = handler;

                //优化;
                // Keep track of which events have been used, for global triggering
                this.global[ type ] = true;
            };

            // Nullify elem to prevent memory leaks in IE
            elem = null;
            /*
             testObject = {
             :
             "events" : {
             "click" : {
             : function() {},
             : function() {},
             : function() {}
             }
             },
             handle : {
             elem : "body"
             }
             }
             */
        },

        global: {},

        // Detach an event or set of events from an element
        remove: function( elem, types, handler ) {
            // don't do events on text and comment nodes
            if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
                return;
            }

            var events = jQuery.data( elem, "events" ), ret, type, fn;

            if ( events ) {
                // Unbind all events for the element
                //清空所有的事件            //没有事件但是有对应的事件命名空间;
                if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
                    for ( type in events ) {
                        //简单的迭代;
                        this.remove( elem, type + (types || "") );
                    }
                } else {
                    //传进来的可能是对象, 字符串;

                    // types is actually an event object here
                    //处理对象的情况;
                    if ( types.type ) {
                        handler = types.handler;
                        types = types.type;
                    };

                    // Handle multiple events separated by a space
                    // jQuery(...).unbind("mouseover mouseout", fn);
                    types = types.split(/\s+/);
                    var i = 0;
                    while ( (type = types[ i++ ]) ) {
                        // Namespaced event handlers
                        var namespaces = type.split(".");
                        type = namespaces.shift();
                        var all = !namespaces.length,
                            cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
                            namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
                            special = this.special[ type ] || {};

                        if ( events[ type ] ) {
                            // remove the given handler for the given type
                            if ( handler ) {
                                fn = events[ type ][ handler.guid ];
                                delete events[ type ][ handler.guid ];

                                // remove all handlers for the given type
                            } else {
                                for ( var handle in events[ type ] ) {
                                    // Handle the removal of namespaced events
                                    if ( all || namespace.test( events[ type ][ handle ].type ) ) {
                                        delete events[ type ][ handle ];
                                    }
                                }
                            }

                            if ( special.remove ) {
                                special.remove.call( elem, namespaces, fn);
                            }

                            // remove generic event handler if no more handlers exist
                            for ( ret in events[ type ] ) {
                                break;
                            }
                            if ( !ret ) {
                                if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
                                    if ( elem.removeEventListener ) {
                                        elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
                                    } else if ( elem.detachEvent ) {
                                        elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
                                    }
                                }
                                ret = null;
                                delete events[ type ];
                            }
                        }
                    }
                }

                // Remove the expando if it's no longer used
                for ( ret in events ) {
                    break;
                }
                if ( !ret ) {
                    var handle = jQuery.data( elem, "handle" );
                    if ( handle ) {
                        handle.elem = null;
                    }
                    jQuery.removeData( elem, "events" );
                    jQuery.removeData( elem, "handle" );
                }
            }
        },

        // bubbling is internal
        //event是必须传的参数, 其余的可以不传;
        trigger: function( event, data, elem /*, bubbling */ ) {
            // Event object or event type
            var type = event.type || event,
                bubbling = arguments[3];

            if ( !bubbling ) {
                //初始化的时候的bubbling是false, 冒泡到父级元素的时候不会走这边;
                event = typeof event === "object" ?
                    // jQuery.Event object, 传进来的就是jQ的事件对象;
                    event[expando] ? event : // xx = xxx===xxx ? yy ? yy : yy : yy 者里面写法不同, 但是是一样样的;
                        // Object literals       // xx = xxx===xxx ? (yy ? yy : yy) : yy
                        jQuery.extend( jQuery.Event(type), event ) :
                    // Just the event type (string)
                    //直接新建一个对象
                    jQuery.Event(type);

                //TODO : 事件对象会有    !click;
                if ( type.indexOf("!") >= 0 ) {
                    event.type = type = type.slice(0, -1);
                    event.exclusive = true;
                };

                // Handle a global trigger
                if ( !elem ) {
                    // Don't bubble custom events when global (to avoid too much overhead)
                    //没有元素的话执行handle会出现各种冒泡的情况,任何元素的冒泡都只执行一次;
                    //这个event是已经fix过的event, 
                    //那么元素的所有事件触发就都不会发生冒泡了, 直接模拟一个一个执行就好了;
                    event.stopPropagation();

                    // Only trigger if we've ever bound an event for it
                    // 获取缓存中的所有guid下的handle下的元素,用这些元素迭代该元素缓存中的指定事件;
                    if ( this.global[ type ] ) {
                        jQuery.each( jQuery.cache, function() {
                            if ( this.events && this.events[type] ) {
                                jQuery.event.trigger( event, data, this.handle.elem );
                            }
                        });
                    };
                };

                // Handle triggering a single element

                // don't do events on text and comment nodes
                if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
                    return undefined;
                }

                // Clean up in case it is reused
                event.result = undefined;
                event.target = elem;

                // Clone the incoming data, if any
                data = jQuery.makeArray( data );
                data.unshift( event );
            };
            //if !bubbling完毕

            event.currentTarget = elem;

            // Trigger the event, it is assumed that "handle" is a function
            var handle = jQuery.data( elem, "handle" );
            if ( handle ) {
                //data的第一个就是event的type, event已经取消冒泡过了, 现在使用手动冒泡;
                //使用handle直接跑就好了;
                handle.apply( elem, data );
            }

            //一大段处理兼容的问题Start
            //如果有通过 DOM0 绑定的元素也直接触发事件;
            var nativeFn, nativeHandler;
            try {
                if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
                    nativeFn = elem[ type ];
                    nativeHandler = elem[ "on" + type ];
                }
                // prevent IE from throwing an error for some elements with some event types, see #3533
            } catch (e) {}

            var isClick = jQuery.nodeName(elem, "a") && type === "click";

            //手动触发以DOM0元素添加的事件;
            // Trigger the native events (except for clicks on links)
            if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !isClick ) {
                this.triggered = true;
                try {
                    elem[ type ]();
                    // prevent IE from throwing an error for some hidden elements
                } catch (e) {};

                // Handle triggering native .onfoo handlers
            } else if ( nativeHandler && elem[ "on" + type ].apply( elem, data ) === false ) {
                event.result = false;
            }
            //一大段处理兼容的问题End;

            this.triggered = false;

            if ( !event.isPropagationStopped() ) {
                var parent = elem.parentNode || elem.ownerDocument;
                //这个完全是没事自己一个一个往上冒泡上去;
                if ( parent ) {
                    jQuery.event.trigger( event, data, parent, true );
                }
            }
        },

        //这个就是高版本的dispatch
        handle: function( event ) {
            // returned undefined or false
            var all, handlers;
            //修复event对象
            event = arguments[0] = jQuery.event.fix( event || window.event );
            event.currentTarget = this;

            // Namespaced event handlers
            var namespaces = event.type.split(".");
            event.type = namespaces.shift();

            // Cache this now, all = true means, any handler
            all = !namespaces.length && !event.exclusive;
            //正则, 不是很懂;
            var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");

            //所有的事件描述对象;
            handlers = ( jQuery.data(this, "events") || {} )[ event.type ];

            for ( var j in handlers ) {
                var handler = handlers[ j ];

                // Filter the functions by class
                //只要找到匹配的t命名空间即可;
                if ( all || namespace.test(handler.type) ) {
                    // Pass in a reference to the handler function itself
                    // So that we can later remove it

                    //修正event的handler的数据和event.data
                    //在事件函数的事件对象可以找到对应的数据;
                    event.handler = handler;
                    event.data = handler.data;

                    //这个是有返回值的;
                    var ret = handler.apply( this, arguments );

                    //如果上一个的ret有返回值, 把这个返回值指向下一个event, 为什么有了延迟对象的感觉;
                    if ( ret !== undefined ) {
                        event.result = ret;
                        if ( ret === false ) {
                            event.preventDefault();
                            event.stopPropagation();
                        }
                    }

                    if ( event.isImmediatePropagationStopped() ) {
                        break;
                    }

                }
            }

            return event.result;
        },

        props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),

        fix: function( event ) {
            //如果event有 expando的话 , 就不是已经fix过的意思;
            if ( event[ expando ] ) {
                return event;
            }

            // store a copy of the original event object
            // and "clone" to set read-only properties
            var originalEvent = event;

            /*设置或者复制事件的几个属性包括
             jQuery1416879535126: true 
             originalEvent: MouseEvent 原始的事件信息
             timeStamp: 1416885709219 //时间戳
             type: "mouseover" //事件类型;
             */
            event = jQuery.Event( originalEvent );

            //altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey 
            //currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey 
            //newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget 
            //screenX screenY shiftKey srcElement target toElement view wheelDelta which;
            for ( var i = this.props.length, prop; i; ) {
                prop = this.props[ --i ];
                event[ prop ] = originalEvent[ prop ];
            }

            //修复浏览器的srcElement为标准的target;
            // Fix target property, if necessary
            if ( !event.target ) {
                event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
            }

            //事件修复;
            // check if target is a textnode (safari)
            if ( event.target.nodeType === 3 ) {
                event.target = event.target.parentNode;
            }

            //这个只有在模拟mouseenter和mouseleave的时候有用;
            // Add relatedTarget, if necessary
            if ( !event.relatedTarget && event.fromElement ) {
                event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
            }

            //修复没有event.pageX 和pageY
            // Calculate pageX/Y if missing and clientX/Y available
            if ( event.pageX == null && event.clientX != null ) {
                var doc = document.documentElement, body = document.body;
                //这个要减去padding的;
                event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
                event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
            };

            // Add which for key events
            if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
                event.which = event.charCode || event.keyCode;
            };

            //MAC下有meta, 让meta等于ctrolKey;
            // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
            if ( !event.metaKey && event.ctrlKey ) {
                event.metaKey = event.ctrlKey;
            };

            // Add which for click: 1 === left; 2 === middle; 3 === right
            // Note: button is not normalized, so don't use it
            if ( !event.which && event.button !== undefined ) {
                event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
            };

            return event;
        },

        // Deprecated, use jQuery.guid instead
        guid: 1E8,

        // Deprecated, use jQuery.proxy instead
        proxy: jQuery.proxy,

        special: {
            ready: {
                // Make sure the ready event is setup
                setup: jQuery.bindReady,
                teardown: jQuery.noop
            },

            live: {
                add: function( proxy, data, namespaces, live ) {
                    jQuery.extend( proxy, data || {} );

                    proxy.guid += data.selector + data.live;
                    jQuery.event.add( this, data.live, liveHandler, data );

                },

                remove: function( namespaces ) {
                    if ( namespaces.length ) {
                        var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");

                        jQuery.each( (jQuery.data(this, "events").live || {}), function() {
                            if ( name.test(this.type) ) {
                                remove++;
                            }
                        });

                        if ( remove < 1 ) {
                            jQuery.event.remove( this, namespaces[0], liveHandler );
                        }
                    }
                },
                special: {}
            },
            beforeunload: {
                setup: function( data, namespaces, fn ) {
                    // We only want to do this special case on windows
                    if ( this.setInterval ) {
                        this.onbeforeunload = fn;
                    }

                    return false;
                },
                teardown: function( namespaces, fn ) {
                    if ( this.onbeforeunload === fn ) {
                        this.onbeforeunload = null;
                    }
                }
            }
        }
    };

//事件对象的的工厂和事件对象的原型定义;
    jQuery.Event = function( src ) {
        // Allow instantiation without the 'new' keyword
        if ( !this.preventDefault ) {
            return new jQuery.Event( src );
        }

        // Event object
        if ( src && src.type ) {
            this.originalEvent = src;
            this.type = src.type;
            // Event type
        } else {
            this.type = src;
        }

        // timeStamp is buggy for some events on Firefox(#3843)
        // So we won't rely on the native value
        this.timeStamp = now();

        // Mark it as fixed
        this[ expando ] = true;
    };

    function returnFalse() {
        return false;
    }
    function returnTrue() {
        return true;
    }

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
    jQuery.Event.prototype = {
        preventDefault: function() {
            this.isDefaultPrevented = returnTrue;

            var e = this.originalEvent;
            if ( !e ) {
                return;
            }

            // if preventDefault exists run it on the original event
            // 标准浏览器下阻止默认事件
            if ( e.preventDefault ) {
                e.preventDefault();
            }
            // otherwise set the returnValue property of the original event to false (IE)
            // IE下阻止默认事件要设置returnValue为false
            e.returnValue = false;
        },
        stopPropagation: function() {
            this.isPropagationStopped = returnTrue;

            var e = this.originalEvent;
            if ( !e ) {
                return;
            }
            // if stopPropagation exists run it on the original event
            if ( e.stopPropagation ) {
                e.stopPropagation();
            }
            // otherwise set the cancelBubble property of the original event to true (IE)
            e.cancelBubble = true;
        },
        stopImmediatePropagation: function() {
            this.isImmediatePropagationStopped = returnTrue;
            this.stopPropagation();
        },
        isDefaultPrevented: returnFalse,
        isPropagationStopped: returnFalse,
        isImmediatePropagationStopped: returnFalse
    };


//下面都是对事件进行修复;
// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
    var withinElement = function( event ) {
            // Check if mouse(over|out) are still within the same parent element
            var parent = event.relatedTarget;

            // Traverse up the tree
            while ( parent && parent !== this ) {
                // Firefox sometimes assigns relatedTarget a XUL element
                // which we cannot access the parentNode property of
                try {
                    parent = parent.parentNode;

                    // assuming we've left the element since we most likely mousedover a xul element
                } catch(e) {
                    break;
                }
            }

            if ( parent !== this ) {
                // set the correct event type
                event.type = event.data;

                // handle event if we actually just moused on to a non sub-element
                jQuery.event.handle.apply( this, arguments );
            }

        },

// In case of event delegation, we only need to rename the event.type,
// liveHandler will take care of the rest.
        delegate = function( event ) {
            event.type = event.data;
            jQuery.event.handle.apply( this, arguments );
        };

// Create mouseenter and mouseleave events
    jQuery.each({
        mouseenter: "mouseover",
        mouseleave: "mouseout"
    }, function( orig, fix ) {
        jQuery.event.special[ orig ] = {
            setup: function( data ) {
                jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
            },
            teardown: function( data ) {
                jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
            }
        };
    });

// submit delegation
    if ( !jQuery.support.submitBubbles ) {

        jQuery.event.special.submit = {
            setup: function( data, namespaces, fn ) {
                if ( this.nodeName.toLowerCase() !== "form" ) {
                    jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
                        var elem = e.target, type = elem.type;

                        if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
                            return trigger( "submit", this, arguments );
                        }
                    });

                    jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
                        var elem = e.target, type = elem.type;

                        if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
                            return trigger( "submit", this, arguments );
                        }
                    });

                } else {
                    return false;
                }
            },

            remove: function( namespaces, fn ) {
                jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
                jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
            }
        };

    };

// change delegation, happens here so we have bind.
    if ( !jQuery.support.changeBubbles ) {

        var formElems = /textarea|input|select/i;

        function getVal( elem ) {
            var type = elem.type, val = elem.value;

            if ( type === "radio" || type === "checkbox" ) {
                val = elem.checked;

            } else if ( type === "select-multiple" ) {
                val = elem.selectedIndex > -1 ?
                    jQuery.map( elem.options, function( elem ) {
                        return elem.selected;
                    }).join("-") :
                    "";

            } else if ( elem.nodeName.toLowerCase() === "select" ) {
                val = elem.selectedIndex;
            }

            return val;
        }

        function testChange( e ) {
            var elem = e.target, data, val;

            if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
                return;
            }

            data = jQuery.data( elem, "_change_data" );
            val = getVal(elem);

            if ( val === data ) {
                return;
            }

            // the current data will be also retrieved by beforeactivate
            if ( e.type !== "focusout" || elem.type !== "radio" ) {
                jQuery.data( elem, "_change_data", val );
            }

            if ( elem.type !== "select" && (data != null || val) ) {
                e.type = "change";
                return jQuery.event.trigger( e, arguments[1], this );
            }
        }

        jQuery.event.special.change = {
            filters: {
                focusout: testChange,

                click: function( e ) {
                    var elem = e.target, type = elem.type;

                    if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
                        return testChange.call( this, e );
                    }
                },

                // Change has to be called before submit
                // Keydown will be called before keypress, which is used in submit-event delegation
                keydown: function( e ) {
                    var elem = e.target, type = elem.type;

                    if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
                        (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
                        type === "select-multiple" ) {
                        return testChange.call( this, e );
                    }
                },

                // Beforeactivate happens also before the previous element is blurred
                // with this event you can't trigger a change event, but you can store
                // information/focus[in] is not needed anymore
                beforeactivate: function( e ) {
                    var elem = e.target;

                    if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
                        jQuery.data( elem, "_change_data", getVal(elem) );
                    }
                }
            },
            setup: function( data, namespaces, fn ) {
                for ( var type in changeFilters ) {
                    jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
                }

                return formElems.test( this.nodeName );
            },
            remove: function( namespaces, fn ) {
                for ( var type in changeFilters ) {
                    jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
                }

                return formElems.test( this.nodeName );
            }
        };

        var changeFilters = jQuery.event.special.change.filters;

    }

    function trigger( type, elem, args ) {
        args[0].type = type;
        return jQuery.event.handle.apply( elem, args );
    }

// Create "bubbling" focus and blur events
    if ( document.addEventListener ) {
        jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
            jQuery.event.special[ fix ] = {
                setup: function() {
                    this.addEventListener( orig, handler, true );
                },
                //teardown是拆卸的意思;
                teardown: function() {
                    this.removeEventListener( orig, handler, true );
                }
            };

            function handler( e ) {
                e = jQuery.event.fix( e );
                e.type = fix;
                return jQuery.event.handle.call( this, e );
            }
        });
    };

//这个在执行的时候( $("xx").bind() )的this指向这个选中的元素;
    jQuery.each(["bind", "one"], function( i, name ) {
        jQuery.fn[ name ] = function( type, data, fn ) {
            // Handle object literals
            if ( typeof type === "object" ) {
                for ( var key in type ) {
                    this[ name ](key, data, type[key], fn);
                }
                return this;
            };

            //修正参数;
            if ( jQuery.isFunction( data ) ) {
                thisObject = fn;
                fn = data;
                data = undefined;
            };

            //如果不是one 就直接设置handler为传进来的fn, 否者把handler加了一层壳;
            var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
                //去除绑定handler;
                //this指向fn;
                jQuery( this ).unbind( event, handler );
                return fn.apply( this, arguments );
            }) : fn;


            //现在是直接绑定元素了;
            return type === "unload" && name !== "one" ?
                this.one( type, data, fn, thisObject ) :
                //一般是走这边的; 
                //data可以是是好几个参数的集合;
                this.each(function() {
                    jQuery.event.add( this, type, handler, data );
                });
        };
        //总结,主要是处理是否执行once, 以及each  this;对每一个元素进行绑定;
    });

    jQuery.fn.extend({
        unbind: function( type, fn ) {
            // Handle object literals
            if ( typeof type === "object" && !type.preventDefault ) {
                for ( var key in type ) {
                    this.unbind(key, type[key]);
                }
                return this;
            }

            return this.each(function() {
                jQuery.event.remove( this, type, fn );
            });
        },
        trigger: function( type, data ) {
            return this.each(function() {
                jQuery.event.trigger( type, data, this );
            });
        },
        //triggerHandler不会触发默认动作, 是触发这个集合的第一个元素;
        triggerHandler: function( type, data ) {
            if ( this[0] ) {
                var event = jQuery.Event( type );
                event.preventDefault();
                event.stopPropagation();
                jQuery.event.trigger( event, data, this[0] );
                return event.result;
            }
        },
        /*
         $(document).ready(function(){
         $("button").toggle(function(){
         $("body").css("background-color","green");},
         function(){
         $("body").css("background-color","red");},
         function(){
         $("body").css("background-color","yellow");}
         );
         });
         */
        toggle: function( fn ) {
            // Save reference to arguments for access in closure
            var args = arguments, i = 1;
            //debugger;
            // link all the functions, so any of them can unbind this click handler
            // 在log中看到的arg为 [1,2,3,4,5] ==>> 仿佛就是数组了;
            // Object.prototype.toString.call( args ) ==>> "[object Arguments]";

            //fn.guid = arguments任意一个函数的guid;
            while ( i < args.length ) {
                jQuery.proxy( fn, args[ i++ ] );
            };

            return this.click( jQuery.proxy( fn, function( event ) {
                // Figure out which function to execute
                var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
                jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );

                // Make sure that clicks stop
                event.preventDefault();

                // and execute the function
                return args[ lastToggle ].apply( this, arguments ) || false;
            }));
        },

        hover: function( fnOver, fnOut ) {
            return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
        },

        live: function( type, data, fn ) {
            if ( jQuery.isFunction( data ) ) {
                fn = data;
                data = undefined;
            }

            jQuery( this.context ).bind( liveConvert( type, this.selector ), {
                data: data, selector: this.selector, live: type
            }, fn );

            return this;
        },

        die: function( type, fn ) {
            jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
            return this;
        }
    });

    function liveHandler( event ) {
        var stop = true, elems = [], selectors = [], args = arguments,
            related, match, fn, elem, j, i, data,
            live = jQuery.extend({}, jQuery.data( this, "events" ).live);

        for ( j in live ) {
            fn = live[j];
            if ( fn.live === event.type ||
                fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {

                data = fn.data;
                if ( !(data.beforeFilter && data.beforeFilter[event.type] &&
                    !data.beforeFilter[event.type](event)) ) {
                    selectors.push( fn.selector );
                }
            } else {
                delete live[j];
            }
        }

        match = jQuery( event.target ).closest( selectors, event.currentTarget );

        for ( i = 0, l = match.length; i < l; i++ ) {
            for ( j in live ) {
                fn = live[j];
                elem = match[i].elem;
                related = null;

                if ( match[i].selector === fn.selector ) {
                    // Those two events require additional checking
                    if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
                        related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
                    }

                    if ( !related || related !== elem ) {
                        elems.push({ elem: elem, fn: fn });
                    }
                }
            }
        }

        for ( i = 0, l = elems.length; i < l; i++ ) {
            match = elems[i];
            event.currentTarget = match.elem;
            event.data = match.fn.data;
            if ( match.fn.apply( match.elem, args ) === false ) {
                stop = false;
                break;
            }
        }

        return stop;
    }

    function liveConvert( type, selector ) {
        return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
    };

//快捷添加事件函数的方式;
    jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
        "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
        "change select submit keydown keypress keyup error").split(" "), function( i, name ) {

        // Handle event binding
        jQuery.fn[ name ] = function( fn ) {
            return fn ? this.bind( name, fn ) : this.trigger( name );
        };

        //这个干嘛用呢;
        if ( jQuery.attrFn ) {
            jQuery.attrFn[ name ] = true;
        }
    });

// Prevent memory leaks in IE
// Window isn't included so as not to unbind existing unload events
// More info:
//  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
    /*
     如这种情况;
     (function(){
     var obj={b:document.body};
     document.body.o=obj; // ← circular link is created. document.body.o.b === document.body
     })();
     */
    if ( window.attachEvent && !window.addEventListener ) {
        window.attachEvent("onunload", function() {
            for ( var id in jQuery.cache ) {
                if ( jQuery.cache[ id ].handle ) {
                    // Try/Catch is to handle iframes being unloaded, see #4280
                    //IE的unload自动清空内存中的事件;
                    try {
                        jQuery.event.remove( jQuery.cache[ id ].handle.elem );
                    } catch(e) {}
                }
            }
        });
    }
    /*!
     * Sizzle CSS Selector Engine - v1.0
     *  Copyright 2009, The Dojo Foundation
     *  Released under the MIT, BSD, and GPL Licenses.
     *  More information: http://sizzlejs.com/
     */
    (function(){

        var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
            done = 0,
            toString = Object.prototype.toString,
            hasDuplicate = false,
            baseHasDuplicate = true;

// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
//   Thus far that includes Google Chrome.
        [0, 0].sort(function(){
            baseHasDuplicate = false;
            return 0;
        });

        var Sizzle = function(selector, context, results, seed) {
            results = results || [];
            var origContext = context = context || document;

            if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
                return [];
            }

            if ( !selector || typeof selector !== "string" ) {
                return results;
            }

            var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
                soFar = selector;

            // Reset the position of the chunker regexp (start from head)
            while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
                soFar = m[3];

                parts.push( m[1] );

                if ( m[2] ) {
                    extra = m[3];
                    break;
                }
            }

            if ( parts.length > 1 && origPOS.exec( selector ) ) {
                if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
                    set = posProcess( parts[0] + parts[1], context );
                } else {
                    set = Expr.relative[ parts[0] ] ?
                        [ context ] :
                        Sizzle( parts.shift(), context );

                    while ( parts.length ) {
                        selector = parts.shift();

                        if ( Expr.relative[ selector ] ) {
                            selector += parts.shift();
                        }

                        set = posProcess( selector, set );
                    }
                }
            } else {
                // Take a shortcut and set the context if the root selector is an ID
                // (but not if it'll be faster if the inner selector is an ID)
                if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
                    Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
                    var ret = Sizzle.find( parts.shift(), context, contextXML );
                    context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
                }

                if ( context ) {
                    var ret = seed ?
                    { expr: parts.pop(), set: makeArray(seed) } :
                        Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
                    set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;

                    if ( parts.length > 0 ) {
                        checkSet = makeArray(set);
                    } else {
                        prune = false;
                    }

                    while ( parts.length ) {
                        var cur = parts.pop(), pop = cur;

                        if ( !Expr.relative[ cur ] ) {
                            cur = "";
                        } else {
                            pop = parts.pop();
                        }

                        if ( pop == null ) {
                            pop = context;
                        }

                        Expr.relative[ cur ]( checkSet, pop, contextXML );
                    }
                } else {
                    checkSet = parts = [];
                }
            }

            if ( !checkSet ) {
                checkSet = set;
            }

            if ( !checkSet ) {
                throw "Syntax error, unrecognized expression: " + (cur || selector);
            }

            if ( toString.call(checkSet) === "[object Array]" ) {
                if ( !prune ) {
                    results.push.apply( results, checkSet );
                } else if ( context && context.nodeType === 1 ) {
                    for ( var i = 0; checkSet[i] != null; i++ ) {
                        if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
                            results.push( set[i] );
                        }
                    }
                } else {
                    for ( var i = 0; checkSet[i] != null; i++ ) {
                        if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
                            results.push( set[i] );
                        }
                    }
                }
            } else {
                makeArray( checkSet, results );
            }

            if ( extra ) {
                Sizzle( extra, origContext, results, seed );
                Sizzle.uniqueSort( results );
            }

            return results;
        };

        Sizzle.uniqueSort = function(results){
            if ( sortOrder ) {
                hasDuplicate = baseHasDuplicate;
                results.sort(sortOrder);

                if ( hasDuplicate ) {
                    for ( var i = 1; i < results.length; i++ ) {
                        if ( results[i] === results[i-1] ) {
                            results.splice(i--, 1);
                        }
                    }
                }
            }

            return results;
        };

        Sizzle.matches = function(expr, set){
            return Sizzle(expr, null, null, set);
        };

        Sizzle.find = function(expr, context, isXML){
            var set, match;

            if ( !expr ) {
                return [];
            }

            for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
                var type = Expr.order[i], match;

                if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
                    var left = match[1];
                    match.splice(1,1);

                    if ( left.substr( left.length - 1 ) !== "\\" ) {
                        match[1] = (match[1] || "").replace(/\\/g, "");
                        set = Expr.find[ type ]( match, context, isXML );
                        if ( set != null ) {
                            expr = expr.replace( Expr.match[ type ], "" );
                            break;
                        }
                    }
                }
            }

            if ( !set ) {
                set = context.getElementsByTagName("*");
            }

            return {set: set, expr: expr};
        };

        Sizzle.filter = function(expr, set, inplace, not){
            var old = expr, result = [], curLoop = set, match, anyFound,
                isXMLFilter = set && set[0] && isXML(set[0]);

            while ( expr && set.length ) {
                for ( var type in Expr.filter ) {
                    if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
                        var filter = Expr.filter[ type ], found, item, left = match[1];
                        anyFound = false;

                        match.splice(1,1);

                        if ( left.substr( left.length - 1 ) === "\\" ) {
                            continue;
                        }

                        if ( curLoop === result ) {
                            result = [];
                        }

                        if ( Expr.preFilter[ type ] ) {
                            match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

                            if ( !match ) {
                                anyFound = found = true;
                            } else if ( match === true ) {
                                continue;
                            }
                        }

                        if ( match ) {
                            for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
                                if ( item ) {
                                    found = filter( item, match, i, curLoop );
                                    var pass = not ^ !!found;

                                    if ( inplace && found != null ) {
                                        if ( pass ) {
                                            anyFound = true;
                                        } else {
                                            curLoop[i] = false;
                                        }
                                    } else if ( pass ) {
                                        result.push( item );
                                        anyFound = true;
                                    }
                                }
                            }
                        }

                        if ( found !== undefined ) {
                            if ( !inplace ) {
                                curLoop = result;
                            }

                            expr = expr.replace( Expr.match[ type ], "" );

                            if ( !anyFound ) {
                                return [];
                            }

                            break;
                        }
                    }
                }

                // Improper expression
                if ( expr === old ) {
                    if ( anyFound == null ) {
                        throw "Syntax error, unrecognized expression: " + expr;
                    } else {
                        break;
                    }
                }

                old = expr;
            }

            return curLoop;
        };

        var Expr = Sizzle.selectors = {
            order: [ "ID", "NAME", "TAG" ],
            match: {
                ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
                CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
                NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
                ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
                TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
                CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
                POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
                PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
            },
            leftMatch: {},
            attrMap: {
                "class": "className",
                "for": "htmlFor"
            },
            attrHandle: {
                href: function(elem){
                    return elem.getAttribute("href");
                }
            },
            relative: {
                "+": function(checkSet, part){
                    var isPartStr = typeof part === "string",
                        isTag = isPartStr && !/\W/.test(part),
                        isPartStrNotTag = isPartStr && !isTag;

                    if ( isTag ) {
                        part = part.toLowerCase();
                    }

                    for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
                        if ( (elem = checkSet[i]) ) {
                            while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}

                            checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
                                elem || false :
                                elem === part;
                        }
                    }

                    if ( isPartStrNotTag ) {
                        Sizzle.filter( part, checkSet, true );
                    }
                },
                ">": function(checkSet, part){
                    var isPartStr = typeof part === "string";

                    if ( isPartStr && !/\W/.test(part) ) {
                        part = part.toLowerCase();

                        for ( var i = 0, l = checkSet.length; i < l; i++ ) {
                            var elem = checkSet[i];
                            if ( elem ) {
                                var parent = elem.parentNode;
                                checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
                            }
                        }
                    } else {
                        for ( var i = 0, l = checkSet.length; i < l; i++ ) {
                            var elem = checkSet[i];
                            if ( elem ) {
                                checkSet[i] = isPartStr ?
                                    elem.parentNode :
                                    elem.parentNode === part;
                            }
                        }

                        if ( isPartStr ) {
                            Sizzle.filter( part, checkSet, true );
                        }
                    }
                },
                "": function(checkSet, part, isXML){
                    var doneName = done++, checkFn = dirCheck;

                    if ( typeof part === "string" && !/\W/.test(part) ) {
                        var nodeCheck = part = part.toLowerCase();
                        checkFn = dirNodeCheck;
                    }

                    checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
                },
                "~": function(checkSet, part, isXML){
                    var doneName = done++, checkFn = dirCheck;

                    if ( typeof part === "string" && !/\W/.test(part) ) {
                        var nodeCheck = part = part.toLowerCase();
                        checkFn = dirNodeCheck;
                    }

                    checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
                }
            },
            find: {
                ID: function(match, context, isXML){
                    if ( typeof context.getElementById !== "undefined" && !isXML ) {
                        var m = context.getElementById(match[1]);
                        return m ? [m] : [];
                    }
                },
                NAME: function(match, context){
                    if ( typeof context.getElementsByName !== "undefined" ) {
                        var ret = [], results = context.getElementsByName(match[1]);

                        for ( var i = 0, l = results.length; i < l; i++ ) {
                            if ( results[i].getAttribute("name") === match[1] ) {
                                ret.push( results[i] );
                            }
                        }

                        return ret.length === 0 ? null : ret;
                    }
                },
                TAG: function(match, context){
                    return context.getElementsByTagName(match[1]);
                }
            },
            preFilter: {
                CLASS: function(match, curLoop, inplace, result, not, isXML){
                    match = " " + match[1].replace(/\\/g, "") + " ";

                    if ( isXML ) {
                        return match;
                    }

                    for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
                        if ( elem ) {
                            if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
                                if ( !inplace ) {
                                    result.push( elem );
                                }
                            } else if ( inplace ) {
                                curLoop[i] = false;
                            }
                        }
                    }

                    return false;
                },
                ID: function(match){
                    return match[1].replace(/\\/g, "");
                },
                TAG: function(match, curLoop){
                    return match[1].toLowerCase();
                },
                CHILD: function(match){
                    if ( match[1] === "nth" ) {
                        // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
                        var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
                            match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
                                !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);

                        // calculate the numbers (first)n+(last) including if they are negative
                        match[2] = (test[1] + (test[2] || 1)) - 0;
                        match[3] = test[3] - 0;
                    }

                    // TODO: Move to normal caching system
                    match[0] = done++;

                    return match;
                },
                ATTR: function(match, curLoop, inplace, result, not, isXML){
                    var name = match[1].replace(/\\/g, "");

                    if ( !isXML && Expr.attrMap[name] ) {
                        match[1] = Expr.attrMap[name];
                    }

                    if ( match[2] === "~=" ) {
                        match[4] = " " + match[4] + " ";
                    }

                    return match;
                },
                PSEUDO: function(match, curLoop, inplace, result, not){
                    if ( match[1] === "not" ) {
                        // If we're dealing with a complex expression, or a simple one
                        if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
                            match[3] = Sizzle(match[3], null, null, curLoop);
                        } else {
                            var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
                            if ( !inplace ) {
                                result.push.apply( result, ret );
                            }
                            return false;
                        }
                    } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
                        return true;
                    }

                    return match;
                },
                POS: function(match){
                    match.unshift( true );
                    return match;
                }
            },
            filters: {
                enabled: function(elem){
                    return elem.disabled === false && elem.type !== "hidden";
                },
                disabled: function(elem){
                    return elem.disabled === true;
                },
                checked: function(elem){
                    return elem.checked === true;
                },
                selected: function(elem){
                    // Accessing this property makes selected-by-default
                    // options in Safari work properly
                    elem.parentNode.selectedIndex;
                    return elem.selected === true;
                },
                parent: function(elem){
                    return !!elem.firstChild;
                },
                empty: function(elem){
                    return !elem.firstChild;
                },
                has: function(elem, i, match){
                    return !!Sizzle( match[3], elem ).length;
                },
                header: function(elem){
                    return /h\d/i.test( elem.nodeName );
                },
                text: function(elem){
                    return "text" === elem.type;
                },
                radio: function(elem){
                    return "radio" === elem.type;
                },
                checkbox: function(elem){
                    return "checkbox" === elem.type;
                },
                file: function(elem){
                    return "file" === elem.type;
                },
                password: function(elem){
                    return "password" === elem.type;
                },
                submit: function(elem){
                    return "submit" === elem.type;
                },
                image: function(elem){
                    return "image" === elem.type;
                },
                reset: function(elem){
                    return "reset" === elem.type;
                },
                button: function(elem){
                    return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
                },
                input: function(elem){
                    return /input|select|textarea|button/i.test(elem.nodeName);
                }
            },
            setFilters: {
                first: function(elem, i){
                    return i === 0;
                },
                last: function(elem, i, match, array){
                    return i === array.length - 1;
                },
                even: function(elem, i){
                    return i % 2 === 0;
                },
                odd: function(elem, i){
                    return i % 2 === 1;
                },
                lt: function(elem, i, match){
                    return i < match[3] - 0;
                },
                gt: function(elem, i, match){
                    return i > match[3] - 0;
                },
                nth: function(elem, i, match){
                    return match[3] - 0 === i;
                },
                eq: function(elem, i, match){
                    return match[3] - 0 === i;
                }
            },
            filter: {
                PSEUDO: function(elem, match, i, array){
                    var name = match[1], filter = Expr.filters[ name ];

                    if ( filter ) {
                        return filter( elem, i, match, array );
                    } else if ( name === "contains" ) {
                        return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
                    } else if ( name === "not" ) {
                        var not = match[3];

                        for ( var i = 0, l = not.length; i < l; i++ ) {
                            if ( not[i] === elem ) {
                                return false;
                            }
                        }

                        return true;
                    } else {
                        throw "Syntax error, unrecognized expression: " + name;
                    }
                },
                CHILD: function(elem, match){
                    var type = match[1], node = elem;
                    switch (type) {
                        case 'only':
                        case 'first':
                            while ( (node = node.previousSibling) )     {
                                if ( node.nodeType === 1 ) {
                                    return false;
                                }
                            }
                            if ( type === "first" ) {
                                return true;
                            }
                            node = elem;
                        case 'last':
                            while ( (node = node.nextSibling) )     {
                                if ( node.nodeType === 1 ) {
                                    return false;
                                }
                            }
                            return true;
                        case 'nth':
                            var first = match[2], last = match[3];

                            if ( first === 1 && last === 0 ) {
                                return true;
                            }

                            var doneName = match[0],
                                parent = elem.parentNode;

                            if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
                                var count = 0;
                                for ( node = parent.firstChild; node; node = node.nextSibling ) {
                                    if ( node.nodeType === 1 ) {
                                        node.nodeIndex = ++count;
                                    }
                                }
                                parent.sizcache = doneName;
                            }

                            var diff = elem.nodeIndex - last;
                            if ( first === 0 ) {
                                return diff === 0;
                            } else {
                                return ( diff % first === 0 && diff / first >= 0 );
                            }
                    }
                },
                ID: function(elem, match){
                    return elem.nodeType === 1 && elem.getAttribute("id") === match;
                },
                TAG: function(elem, match){
                    return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
                },
                CLASS: function(elem, match){
                    return (" " + (elem.className || elem.getAttribute("class")) + " ")
                        .indexOf( match ) > -1;
                },
                ATTR: function(elem, match){
                    var name = match[1],
                        result = Expr.attrHandle[ name ] ?
                            Expr.attrHandle[ name ]( elem ) :
                            elem[ name ] != null ?
                                elem[ name ] :
                                elem.getAttribute( name ),
                        value = result + "",
                        type = match[2],
                        check = match[4];

                    return result == null ?
                        type === "!=" :
                        type === "=" ?
                            value === check :
                            type === "*=" ?
                                value.indexOf(check) >= 0 :
                                type === "~=" ?
                                    (" " + value + " ").indexOf(check) >= 0 :
                                    !check ?
                                        value && result !== false :
                                        type === "!=" ?
                                            value !== check :
                                            type === "^=" ?
                                                value.indexOf(check) === 0 :
                                                type === "$=" ?
                                                    value.substr(value.length - check.length) === check :
                                                    type === "|=" ?
                                                        value === check || value.substr(0, check.length + 1) === check + "-" :
                                                        false;
                },
                POS: function(elem, match, i, array){
                    var name = match[2], filter = Expr.setFilters[ name ];

                    if ( filter ) {
                        return filter( elem, i, match, array );
                    }
                }
            }
        };

        var origPOS = Expr.match.POS;

        for ( var type in Expr.match ) {
            Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
            Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
                return "\\" + (num - 0 + 1);
            }));
        }

        var makeArray = function(array, results) {
            array = Array.prototype.slice.call( array, 0 );

            if ( results ) {
                results.push.apply( results, array );
                return results;
            }

            return array;
        };

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
        try {
            Array.prototype.slice.call( document.documentElement.childNodes, 0 );

// Provide a fallback method if it does not work
        } catch(e){
            makeArray = function(array, results) {
                var ret = results || [];

                if ( toString.call(array) === "[object Array]" ) {
                    Array.prototype.push.apply( ret, array );
                } else {
                    if ( typeof array.length === "number" ) {
                        for ( var i = 0, l = array.length; i < l; i++ ) {
                            ret.push( array[i] );
                        }
                    } else {
                        for ( var i = 0; array[i]; i++ ) {
                            ret.push( array[i] );
                        }
                    }
                }

                return ret;
            };
        }

        var sortOrder;

        if ( document.documentElement.compareDocumentPosition ) {
            sortOrder = function( a, b ) {
                if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
                    if ( a == b ) {
                        hasDuplicate = true;
                    }
                    return a.compareDocumentPosition ? -1 : 1;
                }

                var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
                if ( ret === 0 ) {
                    hasDuplicate = true;
                }
                return ret;
            };
        } else if ( "sourceIndex" in document.documentElement ) {
            sortOrder = function( a, b ) {
                if ( !a.sourceIndex || !b.sourceIndex ) {
                    if ( a == b ) {
                        hasDuplicate = true;
                    }
                    return a.sourceIndex ? -1 : 1;
                }

                var ret = a.sourceIndex - b.sourceIndex;
                if ( ret === 0 ) {
                    hasDuplicate = true;
                }
                return ret;
            };
        } else if ( document.createRange ) {
            sortOrder = function( a, b ) {
                if ( !a.ownerDocument || !b.ownerDocument ) {
                    if ( a == b ) {
                        hasDuplicate = true;
                    }
                    return a.ownerDocument ? -1 : 1;
                }

                var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
                aRange.setStart(a, 0);
                aRange.setEnd(a, 0);
                bRange.setStart(b, 0);
                bRange.setEnd(b, 0);
                var ret = aRange.compareBoundaryPoints(Range.

相关文章: