zoukankan      html  css  js  c++  java
  • jQuery源码06-jQuery = function(){};给JQ对象,添加一些方法和属性,extend : JQ的继承方法,jQuery.extend()

    /*!
     * Includes Sizzle.js    选择器,独立的库
     * http://sizzlejs.com/
     */
    (function( window, undefined ) {
    //"use strict";
    var
        // rootjQuery = jQuery(document) = $();压缩有用
        rootjQuery,
    
        // dom是否加载完
        readyList,
    
        // core_strundefined == 'undefined'
        core_strundefined = typeof undefined,
    
        // Use the correct document accordingly with window argument (sandbox)
        location = window.location,
        document = window.document,
        docElem = document.documentElement,
    
        // 接受外部对jQuery,$的改变,报讯在_jQuery,_$中,
        _jQuery = window.jQuery,
        _$ = window.$,
    
        //class2type = { '[Object String]' : 'string' , '[Object Array]' : 'array' }
        class2type = {},
    
        // 没有用处
        core_deletedIds = [],
    
        core_version = "2.0.3",
    
        // 将对象方法的地址保存在变量中,后面用call调用。
        /*
        var    core_deletedIds = [],
         core_version = "2.0.3",
         core_push = core_deletedIds.push,
         core_trim = core_version.trim;
         alert(core_push);
        function F(){
            this.pu = core_push;
            this.tr = core_trim;
            this.ar = new Array();
            this.df = function(){}
        }
        var f1 = new F();
        core_push.call(f1.ar,1,2,3,4);
        f1.pu.call(f1.ar,1,2,3,4)
        //f.ar.core_push(1,2,3,4);  //f.ar没有core_push方法
        alert(f1.ar.toString());
        
        var f2 = new F();
        alert(f2.pu === f1.pu);//TRUE
        alert(f2.df === f1.df);//false
        alert(f2.tr === f1.tr);//TRUE
        alert(f2.ar === f1.ar);//false
    
        function F(){
            this.a = 1;
            this.f = function(){alert(2);}
        }
        var f1 = new F();
        var f2 = new F();
        alert(f1.f == f2.f);//false
        var f1f = f1.f;
        
        function N(){
            this.f = f1f;
        }
        var n1 = new N();
        var n2 = new N();
        alert(n1.f == n2.f);//true
        alert(n1.f === n2.f);//true
        */
        core_concat = core_deletedIds.concat,
        core_push = core_deletedIds.push,
        core_slice = core_deletedIds.slice,
        core_indexOf = core_deletedIds.indexOf,
        core_toString = class2type.toString,
        core_hasOwn = class2type.hasOwnProperty,
        core_trim = core_version.trim,
        
    
        // []表示任意一个,?表示0、1个,d表示数字,*表示任意多个,.单个非回车换行的字符,.字符点,|是或者,d*.| 数字加小数点或者什么都没有,[eE]科学计数法
        core_pnum = /[+-]?(?:d*.|)d+(?:[eE][+-]?d+|)/.source,
    
        // S是空格
        core_rnotwhite = /S+/g,
    
        // 正则中不加g的时候,会把整体匹配到还会匹配整项,?:表示外层的括号不是子项,小括号是2个子项,
        //match = ['#div1',null,'div1'];  //$('#div1')
        rquickExpr = /^(?:s*(<[wW]+>)[^>]* | #([w-]*))$/,
    
        // 匹配空标签<p></p>
        rsingleTag = /^<(w+)s*/?>(?:</1>|)$/,
    
        // Matches dashed string for camelizing
        rmsPrefix = /^-ms-/,
        rdashAlpha = /-([da-z])/gi,
    
        // Used by jQuery.camelCase as callback to replace()
        fcamelCase = function( all, letter ) {
            return letter.toUpperCase();
        },
    
        //匿名函数全局作用域,dom加载完成执行的方法
        completed = function() {
            document.removeEventListener( "DOMContentLoaded", completed, false );
            window.removeEventListener( "load", completed, false );
            jQuery.ready();
        };
    
        /*
        function Aaa(){
        }
        Aaa.prototype.init = function(){
        };
        Aaa.prototype.css = function(){
        };
        var a1 = new Aaa();
        a1.init();//prototype里的方法一般用对象调用
        a1.css();
    
    
        function jQuery(){
            return new jQuery.prototype.init();//返回init类的对象
        }
        jQuery.prototype.init = function(){
        };
        jQuery.prototype.css = function(){
        };
        jQuery.prototype.init.prototype = jQuery.prototype;//init类的原型等于jQuery的原型,init对象就可以使用jQuery原型里的方法
        //外部使用
        jQuery().css();
        
        */
        
    // $() == jQuery(),这个函数返回对象,
    jQuery = function( selector, context ) {
        //jQuery.fn=jQuery.prototype={init:function(){}},fn就指向prototype,init就是prototype里面的方法,一般用类的对象来调用。
        //jQuery()、$()返回的是init()类的对象,并且执行了init函数里面的方法,执行初始化。
        //$(),jQuery()传的参数都是传给了init()方法里面去了
        return new jQuery.fn.init( selector, context, rootjQuery );
        },
    jQuery.fn.init.prototype = jQuery.fn;//init类的原型等于jQuery的原型,init对象就可以使用jQuery原型里的方法
    
    jQuery.fn = jQuery.prototype = {            //给类jQuery增加静态属性fn,修改函数的prototype并增加属性和方法
        jquery: core_version,
    
        constructor: jQuery,//不回指就是object
        //$("a,b,c")都是调用的是init方法,new init(a,b,c),
        //$('li','ul')//选择ul下面的li,  
        //return new jQuery.fn.init(),init函数执行,如果有return就返回return里面的东西(return的要是引用对象,否则返回init类的实例对象)。
        init: function( selector, context, rootjQuery ) {
            var match, elem;
    
            // $(""), $(null), $(undefined), $(false) 判空
            if ( !selector ) {
                return this;//返回init函数类的对象
            }
    
            // $('#div1') $('.box') $('div')  $('#div1 div.box') $('<li>')  $('<li>1</li><li>2</li>')//创建字符串标签,$('li','ul')//选择ul下面的li, 都是strings类型。
            if ( typeof selector === "string" ) {
                if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
                    // 标签<p>,match是进来的时候定义的,拼接数组,
                    //$('<li>')   $('<li>1</li><li>2</li>')
                    //match = [ null, '<li>', null ];
                    //match = [ null, '<li>1</li><li>2</li>', null ];
                    match = [ null, selector, null ];
    
                } else {
                    /*不是标签,$('#div1') $('.box') $('div')  $('#div1 div.box') $('<li>hello')
                    rquickExpr = /^(?:s*(<[wW]+>)[^>]* | #([w-]*))$/,
                    match = null;  //$('.box') $('div')  $('#div1 div.box')
                    match = ['#div1',null,'div1'];  //$('#div1')
                    match = ['<li>hello','<li>',null];  //$('<li>hello')
                    */
                    match = rquickExpr.exec( selector );
                }
    
                // 创建标签或者根据id查找,$('<li>')  $('#div1')  
                if ( match && (match[1] || !context) ) {
    
                    //创建标签 $('<li>')
                    if ( match[1] ) {
                        //第二个参数context是创建标签的上下文,$('<li>',$(document)),用于iframe中,
                        context = context instanceof jQuery ? context[0] : context;
    
                        // $('<li>1</li><li>2</li>').appendTo( ' ul ' );
                        //merge方法 把 $('<li>1</li><li>2</li>')变成json = {0 : 'li',1 : 'li',length : 2},return this就是这个json并返回出去,就可以appendTo到ul上了。$()返回你需要的任意类型this对象。
                        jQuery.merge( this, jQuery.parseHTML(
                        //parseHTML方法把<li>1</li><li>2</li>变成li数组[li,li],match = [ null, '<li>1</li><li>2</li>', null ];
                        //new的时候this指的是本类对象,
                            match[1],
                            context && context.nodeType ? context.ownerDocument || context : document,
                            true
                        ) );
    
                        // 添加标签并且加属性,$('<li></li>',{title : 'hi',html : 'abcd',css : {background:'red'}}).appendTo( 'ul' );
                        //rsingleTag正则匹配单标签。<li>、<li></li>可以,<li></li><li></li>不行,isPlainObject判断第二个参数是json
                        if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
                            for ( match in context ) {
                            // {html:abcd},this[html]是一个函数,就执行这个函数this[html]('abcd'),
                                if ( jQuery.isFunction( this[ match ] ) ) {
                                    this[ match ]( context[ match ] );
    
                                // {title:'hi'},this.attr(title,'hi'),
                                } else {
                                    this.attr( match, context[ match ] );
                                }
                            }
                        }
    
                        return this;
    
                    // $('#div1') ,id选择器,match = ['#div1',null,'div1'];  
                    } else {
                        elem = document.getElementById( match[2] );//根据id获取element,
    
                        //Blackberry 4.6仅仅判断elem存在是不行的,还要判断他父节点存在
                        if ( elem && elem.parentNode ) {
                            // Inject the element directly into the jQuery object
                            this.length = 1;
                            this[0] = elem;//给对象添加属性名为0值为elem,this[0]设置获取值,不能通过this.0设置获取值。
                            /*
                            function F(a){
                                return new init();//this是F对象
                            }
                            function init(a){
                                this.length = 1;
                                this[0] = document.getElementById("a");
                                alert(this[0].innerHTML);
                                return this;
                            }
                            var f = F();
                            alert(f[0].innerHTML);
                            */
                        }
    
                        this.context = document;
                        this.selector = selector;//'#div1'
                        return this;
                    }
    
                // HANDLE: $(expr, $(...))
                //jquery: core_version = "2.0.3",
                } else if ( !context || context.jquery ) {
                    //context不存在或者context存在且context的jquery存在
                    //( context || rootjQuery )context存在不走后面,rootjQuery  = jQuery(document),context.find()  或者  rootjQuery.find
                    //$('ul',$(document)).find('li');走这里,$(document)是init对象有jquery属性,jquery是init方法的属性,就是判断context是不是init对象或者说jQuery对象。
                    return ( context || rootjQuery ).find( selector );
    
                // HANDLE: $(expr, context)
                // (which is just equivalent to: $(context).find(expr)
                } else {
                    //context存在并且context的jquery属性不存在
                    //$('ul',document).find('li');走这里
                    //constructor: jQuery,constructor就是jQuery函数,jQuery(document).find,window.$ = jQuery;相当于$(document).find,
                    //constructor和函数名一样,都是指的是函数地址,
                    return this.constructor( context ).find( selector );
                }
    
            // selector !== "string" : $(DOMElement),$(this)  $(document)
            } else if ( selector.nodeType ) {//节点都有nodeType属性
                this.context = this[0] = selector;
                this.length = 1;
                return this;
    
            // HANDLE: $(function)  $(function(){})
            //$(function(){}) 是后面的简写 $(document).ready(function(){});
            } else if ( jQuery.isFunction( selector ) ) {
                // rootjQuery = jQuery(document);
                return rootjQuery.ready( selector );
            }
            //$([])  $({})  $( $('#div1') ) ===  $('#div1') ,如果传的是jquery对象$('#div1') ,selector = $('#div1'),$('#div1')这个对象有selector属性,selector.selector === '#div1',
            if ( selector.selector !== undefined ) {
                this.selector = selector.selector;//'#div1'
                this.context = selector.context;//document
            }
    
            return jQuery.makeArray( selector, this );//把类似于数组的转成真正的数组,
        },
    
        // 选择到的元素的字符串
        selector: "",
    
        // $('') 返回的new init(),是init对象,或者init方法中返回的引用对象,对象中元素的个数,
        length: 0,
    
        //jQuery函数原型的方法,jQuery函数对象的方法,makeArray是jQuery extend的方法
        // $('div')) : json对象 Object { 0: <div>, 1: <div>, 2: <div>, 3: <div>, length: 4, prevObject: Object, context: HTMLDocument → new%202.html, selector: "div" }
        //$('div').toArray() : Array [ <div>, <div>, <div>, <div> ]
        toArray: function() {//json转数组
            return core_slice.call( this );
        },
    
        // $('div').get(-1).innerHTML = '222222222',$('div')是jQuery返回的this对象,$('div').get()返回的是div的数组,this[ num ]中括号除了数组的下标还可以代表json或者对象的属性。
        get: function( num ) {
            return num == null ?this.toArray() :
                ( num < 0 ? this[ this.length + num ] : this[ num ] );
        },
    
        // Take an array of elements and push it onto the stack (returning the new matched element set)
        //$('div').pushStack( $('span') )
        pushStack: function( elems ) {
            /*
            jQuery = function() {
                alert(1);
                return new jQuery.fn.init();
            },
            jQuery.fn = jQuery.prototype = {//fn是类的静态属性
            //能够调用jQuery原型里(constructor()、pushStack())方法的只能是jQuery对象或者init对象:$('div')。
                    constructor: jQuery,
                    init: function() {
                    },
                    //$('div').pushStack,this是$('div'),
                    pushStack: function() {
                        alert(2);
                        this.constructor();//1,  this是init对象或者jQuery对象$('div'),返回的是新的空init对象
                        constructor();//constructor.call(window),调不了报错,
                    },
            }
            jQuery.fn.init.prototype = jQuery.fn;
            var j = constructor();//window调用不了
            $('div').pushStack();//1,2,1, $('div')是init对象可以调用pushStack()方法
            o = {}
            o.pushStack();//o.pushStack is not a function,能够调用pushStack方法是jQuery的对象后者init对象,
            new jQuery.fn.init().pushStack();//2 1
            */
            //this是调用pushStack方法的对象,能够调用pushStack和constructor()方法的只有jQuery的对象后者init对象,这里this是$('div')(json格式),this.constructor()返回的是新的空参数的init对象(有jQuery原型的属性和方法以及init函数类的属性方法)
            var ret = jQuery.merge( this.constructor(), elems );//返回span集合,elems = $('span')
            ret.prevObject = this;//this = $('div'),$('span').prevObject -> $('div')
            ret.context = this.context;
            return ret;//将$('span')返回出去
            /*
            $('div').pushStack( $('span') ),pushStack()返回span,span的prevObject等于div,css('background','red')只会把span变红,
            end: function() {
                return this.prevObject || this.constructor(null);
            },
        调用end方法就是返回prevObject就实现了栈,多次调用end(),最后返回空,就不处理最后的css方法。
        
        $('div').pushStack( $('span') ).css('background','red').end().end().end().css('background','yellow');
        */
        },
    
        //加强版的for循环,each是原型的方法,就是对象的方法,
        each: function( callback, args ) {
            return jQuery.each( this, callback, args );//这个each是jQuery.extend({})加进去的,
        },
    
        ready: function( fn ) {
            jQuery.ready.promise().done( fn );
            return this;
        },
        /*
            core_slice = core_deletedIds.slice,        core_deletedIds = [],
            $('div').slice(1,3)返回2.3两个div,他的prevObject = $('div')(4个div),css('background','red')就是把2个div变红,end().css('color','blue')把4个div变蓝。
            
            $('div').slice(1,3).css('background','red').end().css('color','blue');
        */
        slice: function() {
            return this.pushStack( core_slice.apply( this, arguments ) );
        },
    
        first: function() {
            return this.eq( 0 );
        },
    
        last: function() {
            return this.eq( -1 );
        },
    //$('div').eq(0).css('background','red');
        eq: function( i ) {
            var len = this.length,//4个div
                j = +i + ( i < 0 ? len : 0 );
            return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );//返回div[0],div[0].prevObject = $('div')(4个div),
        },
        /*var arr = ['a','b','c'];
        arr = $.map(arr,function(elem,i){
            return elem + i;
        });
        alert( arr );//[a0,b1,c2]*/
        map: function( callback ) {
            return this.pushStack( jQuery.map(
                                            this, 
                                            function( elem, i ) {
                                                return callback.call( elem, i, elem );
                                            }
                                        )
                                   );
             },
    
        end: function() {
            return this.prevObject || this.constructor(null);
        },
    
        //内部使用,把数组的方法挂载到了jQuery对象上了,
        push: core_push,//core_push = core_deletedIds.push,core_deletedIds = [],
        sort: [].sort,
        splice: [].splice
    };
    
    //给jQuery类添加静态方法extend,给jQuery的原型添加方法就是添加对象的方法
            /*
                $.extend({     //给jQuery类加静态方法
                    aaa : function(){
                        alert(1);
                    },
                    bbb : function(){
                        alert(2);
                    }
                });
    
                $.fn.extend({     //给jQuery对象加方法
                    aaa : function(){
                        alert(3);
                    },
                    bbb : function(){
                        alert(4);
                    }
                });
                $.aaa();//1
                $.bbb();//2
                $().aaa();//3
                $().bbb();//4     
    $.extend();  -> this -> $(jQuery类)  -> this.aaa  ->  $.aaa()
    $.fn.extend(); -> this -> $.fn(jQuery原型对象) -> this.aaa ->  $().aaa()
                //当写多个对象自变量的时候 , 后面的对象都是扩展到第一个对象身上
                var a = {};
                $.extend( a , { name : 'hello' } , { age : 30 } );
                console.log( a );//  { name : 'hello'  ,  age : 30 }    
    
                深拷贝浅拷贝
            */
    jQuery.extend = jQuery.fn.extend = function() {//extend继承方法的定义,extend就是给自变量的对象或者jQuery类jQuery对象扩展另一个对象的属性。就是涉及到深拷贝浅拷贝。
        var options, name, src, copy, copyIsArray, clone,
    //默认目标元素是第一个参数,arguments[0],i = 1,不做深拷贝deep = false;
    //var a = {};$.extend( a , { name : 'hello',age:12 } , { ss : 30 } 
            target = arguments[0] || {},//第一个参数
            i = 1,
            length = arguments.length,
            deep = false;//默认是浅拷贝
    
        /*  深拷贝
            var a = {};
            var b = {  name : { age : {nn:14} } };
            $.extend( true,a , b );
            */
        if ( typeof target === "boolean" ) {//判断第一个参数是不是布尔值
            deep = target;//true 深拷贝
            target = arguments[1] || {};//目标元素是第二个参数
            i = 2;//目标元素是第二个参数
        }
    
        // 第一个元素不是对象也不是函数,是string或其他,有可能是深拷贝,设置目标元素是空对象
        if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
            target = {};
        }
    
        // 只有一个参数,$.extend({aaa : function(){alert(1);},bbb : function(){alert(2);}),$.fn.extend({aaa : function(){alert(1);},bbb : function(){alert(2);})
    });
        if ( length === i ) {
            target = this;//目标参数就是this,this是$或者$.fn,this指的是函数时候代表函数体,
            --i;//i=0
        }
    
        //多个参数,循环把每个对象赋值到第一个对象,
        //1.var a = {};$.extend( a , { name : 'hello',age:12 } , { ss : 30 } );target=a,deep = false,i = 1,
        //2.$.extend({aaa : function(){alert(1);},bbb : function(){alert(2);}),i=0,deep = false
        //3.1.var a = {}; var b = {  name : {age : {nn:14} } }; $.extend( true,a , b );deep = true,target=a={},i = 2
        for ( ; i < length; i++ ) {
            //1.判空,不能是$.extend( a , null , null ); 1.options是第i个json,
            //2.options={aaa : function(){alert(1);},bbb : function(){alert(2);}
            //3.1.options= {  name : { age : {nn:14} } }
            if ( (options = arguments[ i ]) != null ) {
                //1.遍历第i个json,{ name : 'hello',age:12 }
                for ( name in options ) {
                    //1.target = a = {},src = a[name] = null,a[age] = null,a[ss]=null
                    //2.$[aaa]=null=src,target=$,$[bbb]=null=src
                    //3.1.a[name]=src=null,
                    src = target[ name ];
                    //1.copy = 'hello' copy=12 copy=30
                    //2.copy=function(){alert(1);},copy=function(){alert(2);},
                    //3.1.copy={age : {nn:14} }
                    copy = options[ name ];
    
                    // 1. $.extend( a , { name : a } )防止这种情况
                    //2.$.extend({aaa : $,bbb : $)防止这种情况
                    //3.1.$.extend( true,a , {name:a} )
                    if ( target === copy ) {
                        continue;
                    }
    
                    // 深拷贝
                    //3.1.isPlainObject判断json键对应的值是不是对象,或者数组
                    //copy这个键的值是对象
                    if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                        //src = target[ name ] 如果存在,target[ name ] = jQuery.extend( deep, target[ name ], copy );
                        if ( copyIsArray ) {
                            copyIsArray = false;
                            clone = src && jQuery.isArray(src) ? src : [];
    
                        } else {
                            /*3.1.3 clone=false
                            var a = { name : { job : 'it' } };
                            var b = { name : {age : {n:10}} };
                            $.extend( true , a  , b );            
                            src = { job : 'it' }
                            a = { name : { job : 'it' ,{age : {n:10}}} };  
                            */
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }
    
                        // 3.递归
                        //3.1.a[name]=jQuery.extend( true, {}, {age : {nn:14} } )
                        //3.1.2 a[name]=jQuery.extend( true, { job : 'it' }, {age : {n:10}})
                        //3.1.2 a[age]=jQuery.extend( true, {}, {n:10} )={n:10},a={job : 'it',age : {n:10}}
                        //3.1.3 a[name] = jQuery.extend( true, { job : 'it' }, {age : {n:10}} );   target={job : 'it'}  target[age]=jQuery.extend( deep, {}, {n:10} );target={}  target[n]=10 return{n:10},target[age]={n:10},target={job : 'it',age : {n:10}} return target,a[name]={job : 'it',age : {n:10}}
                        target[ name ] = jQuery.extend( deep, clone, copy );
    
                    //浅拷贝target[ name ] = copy;copy是一个对象的时候就是传递的地址,
                    } else if ( copy !== undefined ) {
                        //1.a[name] = 'hello' a[age] = 12 a[ss]=30 a={name:'hello',age:12,ss:30}
                        //2.$[aaa]=function(){alert(1);},$[bbb]=function(){alert(2);}
                        target[ name ] = copy;
                    }
                }
            }
        }
        return target;
    };
    
    jQuery.extend({//调用extend方法,给jQuery函数增加静态方法,js中直接通过$调用,不需要jquery对象。
    
        // 唯一随机字符串,replace( /D/g, "" )把非数字小数点变为空,例如数据缓存做唯一操作
        expando: "jQuery" + ( core_version + Math.random() ).replace( /D/g, "" ),
    /*
    <script>
    var $ = 123;
    var jQuery = 456;
    js源码里面有    _jQuery = window.jQuery,_$ = window.$,接受外部的改变,保存在_$ = 123,_jQuery=456
    </script>
    <script src="jquery-203.js"></script>
    <script>
    var miaov = $.noConflict(true);
    </script>
    */
        noConflict: function( deep ) {
            if ( window.$ === jQuery ) {//一定相等
                window.$ = _$;//window.$ = 123,jQuery就放弃$了,使用miaov,
            }
    
            if ( deep && window.jQuery === jQuery ) {//一定相等
                window.jQuery = _jQuery;//window.jQuery = 456,jQuery就放弃jQuery了,使用miaov,
            }
    
            return jQuery;
        },
    
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
    
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
    
        /*
        $.getScript('a.js',function(){//动态加载js,异步加载,有可能alert(2)先于a.js加载完
        });
        $(function(){
            alert(2);
        });
        -----------------------------------------
        $.holdReady(true);
        $.getScript('a.js',function(){//动态加载js,异步加载
            $.holdReady(false);//a.js加载完后回调函数执行,释放hold,保证先加载a.js,然后弹出alert(2)
        });
        $(function(){
            alert(2);
        });
        */
        holdReady: function( hold ) {
            if ( hold ) {
                jQuery.readyWait++;//readyWait是将要加到jQery函数的属性,加完之后调用这个方法就可以使用这个变量,holdReady调用多次,readyWait++多次
            } else {
                jQuery.ready( true );//下面
            }
        },
    
        //$.ready()  Handle when the DOM is ready
        ready: function( wait ) {
    
            // --jQuery.readyWait不为0就继续等
            if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
                return;
            }
    
            // isReady是给jQuery类扩展的静态属性
            jQuery.isReady = true;
    
            // If a normal DOM Ready event fired, decrement, and wait if need be
            if ( wait !== true && --jQuery.readyWait > 0 ) {
                return;
            }
    
            // If there are functions bound, to execute
            readyList.resolveWith( document, [ jQuery ] );
    
            // Trigger any bound ready events
            if ( jQuery.fn.trigger ) {
                jQuery( document ).trigger("ready").off("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).
        isFunction: function( obj ) {
            return jQuery.type(obj) === "function";
        },
    
        isArray: Array.isArray,
    
        isWindow: function( obj ) {// $.isWindow(window),通过$调用。js中window有2个作用,1是充当全部对象,2是做浏览器窗口,只有window才有window属性并且等于window。如果obj是undefined、null,undefined === undefined.window=undefined,null === null.window=undefined,所以要判断obj不是undefined或者null(obj != null)。
            return obj != null && obj === obj.window;//undefined是等于null的,null是等于null的,undefined.window返回null,null.window返回null,
        },
    
        //不能用typeof,alert( typeof NaN );//number
        isNumeric: function( obj ) {
            //parseFloat(obj) 可以转的是数字,不可以转的返回NaN,
            //isFinite是原生的方法,判断是不是有限的数字,alert( isFinite( Number.MAX_VALUE + Number.MAX_VALUE ) );//false
            return !isNaN( parseFloat(obj) ) && isFinite( obj );
        },
    
        type: function( obj ) {
            if ( obj == null ) {//obj = null或者undefined
                return String( obj );//'undefined','null'
            }
            //core_toString = {}.toString,
            //alert( {}.toString.call([]));//[object Array]这个判断类型最全
            //jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); });将[object Array]简写成array
            return typeof obj === "object" || typeof obj === "function" ?
                class2type[ core_toString.call(obj) ] || "object" :
                typeof obj;
        },
    
        //判断是否对象自变量
        isPlainObject: function( obj ) {
            //jQuery.type( obj ) !== "object"  不是基本类型
            //obj.nodeType 是一个dom节点,jQuery.type(dom节点)返回object,不是对象自变量,window也不是对象自变量,jQuery.type(window)返回object
            if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
                return false;
            }
            //jQuery.type( window.location) 返回object,不是基本类型不是节点不是window,
            //有constructor属性,core_hasOwn = {}.hasOwnProperty方法,obj.constructor.prototype有没有isPrototypeOf属性,
            try {
                if ( obj.constructor &&
                        !core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
                    return false;
                }
            } catch ( e ) {
                return false;//狐火下执行次数过多会报错
            }
    
            //{},new Object(),
            return true;
        },
    
        //是否为空对象{},[],没有自身的属性和方法(有原型属性也可以遍历出来,不是空对象)
        isEmptyObject: function( obj ) {
            var name;
            for ( name in obj ) {
                return false;
            }
            return true;
        },
    
        error: function( msg ) {// $.error('这是错误');
            throw new Error( msg );
        },
    
        /* keepScripts = true, 可以解析script标签
        把 $('<li>1</li><li>2</li>')变成this = {0 : 'li',1 : 'li',length : 2},data = [ null, '<li>1</li><li>2</li>', null ];
        /*
        var str = '<li></li><li></li>';
        $.parseHTML(str); 返回li的数组
        /*[li, li]
        0: li
        1: li
        length: 2
        __proto__: Array(0) //
    
        var str = '<li></li><li></li><script></script>';
        $.parseHTML(str,document,true);
        //
        [li, li, script]
        0: li
        1: li
        2: script
        length: 3
        __proto__: Array(0)
        //
        */
        parseHTML: function( data, context, keepScripts ) {
            if ( !data || typeof data !== "string" ) {//存不存在,是不是字符串
                return null;
            }
            if ( typeof context === "boolean" ) {//第二个参数就是布尔值,就当第三个参数用,第二个参数是false,
                keepScripts = context;
                context = false;
            }
            context = context || document;//执行上下文只能是document,这个document可以是当前页面的也可以是iframe的,
            var parsed = rsingleTag.exec( data ),//判断是不是单标签<li></li>,<li></li><li></li>是多标签
                scripts = !keepScripts && [];
    
            // 单标签,创建这个标签,返回数组,
            if ( parsed ) {
                return [ context.createElement( parsed[1] ) ];//context是执行上下文,是document对象,创建element和getelement前面都需要这个对象来调用方法而已。
            }
    //多标签,创建dom标签节点
            parsed = jQuery.buildFragment( [ data ], context, scripts );
    
            if ( scripts ) {//keepScripts=true,不删除script标签,keepScripts=false,删除script标签。
                jQuery( scripts ).remove();
            }
    
            return jQuery.merge( [], parsed.childNodes );
        },
    
        //json格式字符串转json,IE678不支持,
        parseJSON: JSON.parse,
    
        // Cross-browser xml parsing,解析xml,出了json解析还有xml解析,xml是最早的数据形式,后来才有的json,以前都是xml。
        parseXML: function( data ) {
            var xml, tmp;
            if ( !data || typeof data !== "string" ) {//不存在不是string
                return null;
            }
    
            // Support: IE678不支持,支持IE9。IE678出错了不会进入catch,而是创建一个xml携带<parsererror>错误的信息</parsererror>
            try {
                tmp = new DOMParser();//创建解析xml的对象,最早火狐支持,后来都开始支持了。
                xml = tmp.parseFromString( data , "text/xml" );
            } catch ( e ) {
                xml = undefined;//data必须是完整的xml,不能是html,
            }
            
            if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
                jQuery.error( "Invalid XML: " + data );
            }
            return xml;
        },
    
        noop: function() {},
    
        // Evaluates a script in a global context,全局解析js,
        /*
        function test() {
            jQuery.globalEval( "var newVar = true;" )
            var newVar1 = true;
        }
        test();
        alert( newVar );
        alert( newVar1 );
        
        function test(){
            var i = eval;
            i('var a = 1');
            eval('var b = 2');
            window.eval('var c = 3');
            alert( "s"+a );
            alert( "s"+b );
            alert( "s"+c );
            
        }
        test();
        alert( a );//1
        alert( b );//buxing
        alert( c );//3
        */
        globalEval: function( code ) {
            var script,
                    indirect = eval;
    
            code = jQuery.trim( code );//去前后空格
    
            if ( code ) {
                // 创建script标签,加文本,加入到head中,删除script标签
                if ( code.indexOf("use strict") === 1 ) {
                    script = document.createElement("script");
                    script.text = code;
                    document.head.appendChild( script ).parentNode.removeChild( script );
                } else {
                    indirect( code );//eval来解析
                }
            }
        },
    
        // 把css样式转成js能够接受的,比如js不能接受横杆
        /*
        (function(){
            var a,b=1,c=2;//全局闭包作用域,内部都可以通过闭包链来找到这个外部变量
            var f = function(o){
                for(i in o){
                    alert(i+"--"+o[i]());//camelCase--3
                }
            }
            f({
                camelCase: function( string ) {
                    return b+c;
                },
            })
        })()
        */
        //margin-top ->  marginTop  -ms-transform -> msTransform -moz-transform -> MozTransform
        //rmsPrefix = /^-ms-/, rdashAlpha = /-([da-z])/gi,    fcamelCase = function( all, letter ) { return letter.toUpperCase(); },
        camelCase: function( string ) {
            return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
        },
        /*
        replace后面传递函数:
        rmsPrefix = /^-ms-/;
        rdashAlpha = /-([da-z])/gi;
        fcamelCase = function( all, letter ) { 
            alert(all);//-t,正则匹配到的整体
            alert(letter);//t,正则里面的子项
            return letter.toUpperCase(); 
        };
        camelCase=function( string ) {
                var d = string.replace( rmsPrefix, "ms-" );//ms-transform
                var g = d.replace( rdashAlpha, fcamelCase );//msTransform
                return g;
            },
        alert(camelCase('-ms-transform'));
        */
        
        //判断节点的名字是不是指定的名字
        nodeName: function( elem, name ) {
            return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
        },
    
        // args is for 内部使用
        /**
        var arr = ['a','b','c','d'];
        var json = { name : 'hello' , age : 20 };
        $.each(json , function(i,value){//下标  每一个值
            alert(value);
            return false;//return false了,只执行一次
        });
        */
        each: function( obj, callback, args ) {
            var value,
                i = 0,
                length = obj.length,//数组有长度,json没有长度,也有可能json里面有一个length属性,
                isArray = isArraylike( obj );//是不是类数组或者真正数组
    
            if ( args ) {//内部使用,平时不传
                if ( isArray ) {
                    for ( ; i < length; i++ ) {
                        value = callback.apply( obj[ i ], args );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                } else {
                    for ( i in obj ) {//遍历json
                        value = callback.apply( obj[ i ], args );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                }
    
            // A special, fast, case for the most common use of each
            } else {
                if ( isArray ) {//数组
                    for ( ; i < length; i++ ) {//回调函数
                        value = callback.call( obj[ i ], i, obj[ i ] );
    
                        if ( value === false ) {//回调函数返回值是false就不循环了
                            break;
                        }
                    }
                } else {//json
                    for ( i in obj ) {
                        value = callback.call( obj[ i ], i, obj[ i ] );
    
                        if ( value === false ) {
                            break;
                        }
                    }
                }
            }
    
            return obj;
        },
    
        trim: function( text ) {
            return text == null ? "" : core_trim.call( text );
        },
    
        // 类似于数组转成真正数组
        /*
        var s = 123;
        console.log( $.makeArray( s ) );//[123]
        console.log( $.makeArray( s , {length:3} ) );//Object {3: 123, length: 4}
        
        var str = {1:1,2:2};
        console.log( $.makeArray( str ) );//[{1:1,2:2}]
        console.log( $.makeArray( str , {length:3} ) );//{3:{1:1,2:2},length: 4}
        */
        makeArray: function( arr, results ) {
            var ret = results || [];
    
            if ( arr != null ) {
                /*Object()将基本类型转成对应的对象类型。
    console.log(Object(123));//Number {[[PrimitiveValue]]: 123}
    console.log(Object('abc'));//String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
    console.log(Object(true));//Boolean {[[PrimitiveValue]]: true}
                */
                if ( isArraylike( Object(arr) ) ) {//'hello'走这里,
                    jQuery.merge( ret,
                        typeof arr === "string" ?
                        [ arr ] : arr
                    );
                } else {//123走这里
                    core_push.call( ret, arr );
                }
            }
    
            return ret;
        },
    
        /*    indexof
        var arr = ['a','b','c','d'];
        alert( $.inArray( 'w' , arr ) ); 
        core_indexOf = [].indexOf,           */
        inArray: function( elem, arr, i ) {//i是从哪里开始查
            return arr == null ? -1 : core_indexOf.call( arr, elem, i );
        },
    
        /*
        $.merge(['a','b'],['c','d']);//["a", "b", "c", "d"]
        $.merge(['a','b'],{0:'c',1:'d'});//["a", "b", "c", "d"]
        $.merge({0:'a',1:'b',length:2},{0:'c',1:'d'});//{0: "a", 1: "b", 2: "c", 3: "d", length: 4}
        $.merge({0:'a',1:'b',length:2},['c','d']);// {0: "a", 1: "b", 2: "c", 3: "d", length: 4}
        */
        merge: function( first, second ) {
            var l = second.length,
                i = first.length,
                j = 0;
            //    $.merge( ['a','b'],['c','d'] );
            if ( typeof l === "number" ) {//json的length不是number,
                for ( ; j < l; j++ ) {
                    first[ i++ ] = second[ j ];
                }
            } else {// $.merge( ['a','b'],{0:'c',1:'d'} );
                while ( second[j] !== undefined ) {
                    first[ i++ ] = second[ j++ ];//second的json的属性还必须是0.1.2
                }
            }
            first.length = i;
            return first;
        },
    
        /*
        var arr = [1,2,3,4];
        arr = $.grep( arr , function( n , i ){//n是每一项,i是下标
            return n>2;
        } , true );
        console.log( arr );//[1,2]
        */
        grep: function( elems, callback, inv ) {
            var retVal,
                ret = [],
                i = 0,
                length = elems.length;
            inv = !!inv;//2个!就把undefined转成false
            for ( ; i < length; i++ ) {
                retVal = !!callback( elems[ i ], i );//2个!就把不是布尔类型的转成相应的布尔值
                if ( inv !== retVal ) {
                    ret.push( elems[ i ] );
                }
            }
    
            return ret;
        },
    
        /*
        var arr = [1,2,3,4];
        arr = $.map( arr , function(n){
            return [n+1];
        } );
        console.log( arr );//[2,3,4,5]
        */
        map: function( elems, callback, arg ) {
            var value,
                i = 0,
                length = elems.length,
                isArray = isArraylike( elems ),
                ret = [];
            if ( isArray ) {
                for ( ; i < length; i++ ) {
                    value = callback( elems[ i ], i, arg );
                    if ( value != null ) {
                        ret[ ret.length ] = value;//末尾追加
                    }
                }
            } else {//json
                for ( i in elems ) {
                    value = callback( elems[ i ], i, arg );
                    if ( value != null ) {
                        ret[ ret.length ] = value;
                    }
                }
            }
            // ret = [[2],[3],[4],[5]]
            return core_concat.apply( [], ret );//[2,3,4,5]
        },
    
        // A global GUID counter for objects
        guid: 1,
    
        /*
        function show(n1,n2){
            alert(n1);
            alert(n2);
            alert(this);
        }
        show();//window
        $.proxy(show,document)(3,4);//改变show的this是document,执行,
        $.proxy(show,document,3)(4);//改变show的this是document,执行,
        $.proxy(show,document,3)//不执行
        */
        proxy: function( fn, context ) {
            var tmp, args, proxy;
            //var obj = {show : function(){}};
            //$(document).click( $.proxy(obj,'show') );//让obj下面的show指向obj
            if ( typeof context === "string" ) {
                context = fn;//context = obj
                fn = tmp;//fn = show
                //变成了$.proxy(show,obj),统一参数格式
            }
    
            if ( !jQuery.isFunction( fn ) ) {
                return undefined;
            }
    
            // 第3个参数3,
            args = core_slice.call( arguments, 2 );
            proxy = function() {//返回的是函数,后面小括号表示这个函数体执行,
                return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
                //[].slice.call( arguments )把arguments转成真正的数组,arguments是后面的参数
            };
    
            // 后期处理事件
            proxy.guid = fn.guid = fn.guid || jQuery.guid++;
    
            return proxy;
        },
    
        // 内部使用,
        /*
        alert( $('#div1').css('width') );
        $('#div1').css('background','yellow');
        $('#div1').css(''yellow');
        $('#div1').css('width','300px');
        $('#div1').css({ background : 'yellow' , width : '300px' });
        */
        access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
    
            //elems=$('#div1'),fn是回调函数,key=background,value=yellow,chainable为真表示设置值为假表示设置值,
            var i = 0,
                length = elems.length,
                bulk = key == null;///没有key就是true,
    
            //设置多组值:..css({ background : 'yellow' , width : '300px' })
            //是object就是json,
            if ( jQuery.type( key ) === "object" ) {
                chainable = true;
                for ( i in key ) {
                    jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
                }
            // 设置一组值:$('#div1').css('width','300px');
            } else if ( value !== undefined ) {
                chainable = true;///不设置就是undefined
                if ( !jQuery.isFunction( value ) ) {
                    raw = true;
                }
                if ( bulk ) {///没有key
                    if ( raw ) {///不是函数
                        fn.call( elems, value );
                        fn = null;
                    } else {///是函数,函数现在不执行,套上一层,里面return时候调用函数
                        bulk = fn;
                        fn = function( elem, key, value ) {
                            return bulk.call( jQuery( elem ), value );
                        };
                    }
                }
    
                if ( fn ) {
                    for ( ; i < length; i++ ) {
                        fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
                    }
                }
            }
                
            //chainable是真就是设置值,
            return chainable ?
                elems :
    
                // Gets
                bulk ?///有没有key值
                    fn.call( elems ) :///有key就调用
                    length ? fn( elems[0], key ) : emptyGet;///又要分长度
        },
    
        now: Date.now,
    
        /*
        alert( $('#div1').width() );//display:none还是获取到了,利用的是swap方法
        alert( $('#div1').get(0).offsetWidth );//原生的宽度方法,display:none就获取不到了    
        */
        swap: function( elem, options, callback, args ) {
            var ret, name,
                old = {};//老的样式
    
            // Remember the old values, and insert the new ones
            for ( name in options ) {
                old[ name ] = elem.style[ name ];//存老的样式
                elem.style[ name ] = options[ name ];//设置新的样式
            }
    
            ret = callback.apply( elem, args || [] );//调用函数获取想要的属性值
    
            // Revert the old values
            for ( name in options ) {
                elem.style[ name ] = old[ name ];//样式还原
            }
    
            return ret;
        }
    });
    
    /* $(function(){}) -->  rootjQuery.ready(function(){})  -->  $(document).ready(function(){})  --> $().ready(function(){}) --> jQuery.ready.promise().done( function(){} )  
            ----------->  addEventListener --> jQuery.ready() --> readyList.resolveWith( document, [ jQuery ] );
            ----------->  readyList.promise( obj ) --> 
    ready: function( fn ) {
        jQuery.ready.promise().done( fn );
        return this;
    },  */
    jQuery.ready.promise = function( obj ) {
        if ( !readyList ) {//是否加载完,刚开始是false,只走进来一次,
    
            readyList = jQuery.Deferred();
    
            if ( document.readyState === "complete" ) {//dom加载完document的属性是完成状态,
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                setTimeout( jQuery.ready );
    
            } else {
    
                /*匿名函数全局作用域,dom加载完成执行的方法
                completed = function() {
                    document.removeEventListener( "DOMContentLoaded", completed, false );
                    window.removeEventListener( "load", completed, false );
                    jQuery.ready();
                      jQuery.ready() --> readyList.resolveWith( document, [ jQuery ] );
                };
                */
                document.addEventListener( "DOMContentLoaded", completed, false );
    
                // A fallback to window.onload, that will always work
                window.addEventListener( "load", completed, false );
            }
        }
        return readyList.promise( obj );
    };
    
    // Populate the class2type map
    jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
        class2type[ "[object " + name + "]" ] = name.toLowerCase();
    });
    
    //是不是数组,特殊数组,带length属性的json
    function isArraylike( obj ) {
        var length = obj.length,
            type = jQuery.type( obj );
    
        if ( jQuery.isWindow( obj ) ) {//是不是window,下面的判断有可能window也满足,
            return false;
        }
    
        if ( obj.nodeType === 1 && length ) {//一组元素节点是类数组
            return true;
        }
        //type !== "function"不加这个,那么有length属性的函数就进去了
        return type === "array" || type !== "function" &&
            ( length === 0 ||
            typeof length === "number" && length > 0 && ( length - 1 ) in obj );
    }
    
    // All jQuery objects should point back to these
    rootjQuery = jQuery(document);
  • 相关阅读:
    A. Ivan the Fool and the Probability Theory
    C2. Good Numbers (hard version)
    C. p-binary
    H. Happy Birthday
    idea使用goeasy实现webSocket
    idea新建一个maven项目
    FreeMaker入门介绍
    mui预加载
    mui底部选项卡切换实现
    BootStrap 学习笔记一
  • 原文地址:https://www.cnblogs.com/yaowen/p/6931558.html
Copyright © 2011-2022 走看看