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);
  • 相关阅读:
    archlinux .bash_history
    Ubuntu环境下挂载新硬盘
    软碟通 UltraISO U启替代品 Win32DiskImager 无设备 无盘符 无u盘 无优盘 解决方案 之diskpart
    delphi Integer overflow
    MSBuild Tools offline
    delphi synedit免费的拼写检查器dll
    git 自定义命令行
    lua编译
    gcc ar
    Windows Subsystem for Linux (WSL)挂载移动硬盘U盘 卸载 c d 盘
  • 原文地址:https://www.cnblogs.com/yaowen/p/6931558.html
Copyright © 2011-2022 走看看