/*! * 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*(<[\w\W]+>)[^>]* | #([\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*(<[\w\W]+>)[^>]* | #([\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);