jQuery源码研究分析学习笔记-静态方法和属性(10)
2016-08-05 10:40
901 查看
jQuery源码中定义了一些重要的静态属性和方法,它们是其他模块实现的基础,整体的源码结构如下
函数fcamelCase ()负责把连字符后的字母转换成为大写并返回
//把window.jQuery和winow.$备份到局部变量_jQuery和_$ _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, jQuery.extend({ //许多 JavaScript 库使用 $ 作为函数或变量名,jQuery 也一样。在 jQuery 中,$ 仅仅是 jQuery 的别名,因此即使不使用 $ 也能保证所有功能性。假如我们需要使用 jQuery 之外的另一 JavaScript 库,我们可以通过调用 $.noConflict() 向该库返回控制权: noConflict: function( deep ) { //若window.$ ===jQuery,则设置window.$为初始化时备份的_$. //只有在当前jQuery库持有全局变量$的情况下,才会释放$的控制器给前一个javascript库 if ( window.$ === jQuery ) { window.$ = _$; } //当deep为true,且window.jQuery===jQuery,则设置window.jQuery为初始化时备份的_jQuery if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // 用于判断传入的参数是否是函数 isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, isWindow: function( obj ) { return obj != null && obj == obj.window; }, isNumeric: function( obj ) { return !isNaN( parseFloat(obj) ) && isFinite( obj ); }, //用于判断参数的内建Javascript类型,如果参数是undefined或null,返回"undefined"或"null";如果参数是Js内部对象,则返回对应的字符串名称;其他情况一律返回"object" type: function( obj ) { return obj == null ? String( obj ) : //toString = Object.prototype.toString //借用Object的原型方法toString()获取obj的字符串表示,返回值的形式为[object class],其中的class是内部对象类,Object.prototype.toString.call(new Date())返回[object Date] class2type[ toString.call(obj) ] || "object"; }, //用于判断传入的参数是否是”纯粹“的对象,是否是对象直接量{}或 new Object()创建的对象 isPlainObject: function( obj ) { //obj可以转换成false,Object.prototype.toString.call(obj)返回的不是[object object ],obj是DOM元素,obj是window对象,满足一个则返回false if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // 检查对象obj是否由构造函数Object()创建, 对象obj含有属性constuctor,由 构造函数创建的对象都有一个constructor属性,默认引用了该对象的构造函数,如果对象obj没有属性constructor,则说明该对象必然是通过对象字面量{} 创建的 if ( obj.constructor && //hasOwn = Object.prototype.hasOwnProperty !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // 检查对象obj的属性是否都是非继承属性,如果没有属性,或者所有的属性都是非继承,怎返回true var key; for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, //用于检查对象是都是空的(不包含属性) isEmptyObject: function( obj ) { //for-in循环会同时枚举非继承属性和从原型对象继承的属性,如果有,则返回false,否则默认返回true for ( var name in obj ) { return false; } return true; }, //接收一个字符串,抛出一个包含了该字符串的异常 error: function( msg ) { throw new Error( msg ); }, //把一个json字符串,解析返回javascript对象,如果传入的残缺的json字符串可能导致抛出异常 parseJSON: function( data ) { //如果不传入参数,或传入空字符串、null、undefined,则返回null if ( typeof data !== "string" || !data ) { return null; } // 移除开头和末尾的空白符,兼容IE6/7 data = jQuery.trim( data ); // 若支持,使用原生的方法JSON.parse()解析JSON字符串,并返回 if ( window.JSON && window.JSON.parse ) { //JSON.parse()和JSON.stringify(),用于JSON字符串和javaScript对象之间的相互转换 //JSON.parse()解析JSON字符串为JSON对象,JSON.stringify()转换JSON对象为JSON字符串 return window.JSON.parse( data ); } // 若不支持JSON.parse(),先检查字符串是否合法, // rvalidchars = /^[\],:{}\s]*$/, // rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, // rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, // rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { return ( new Function( "return " + data ) )(); } jQuery.error( "Invalid JSON: " + data ); }, // 接受一个格式良好的xml字符传,返回解析后的XML文档 parseXML: function( data ) { if ( typeof data !== "string" || !data ) { return null; } var xml, tmp; try { if ( window.DOMParser ) { //IE9+和其他标准浏览器 tmp = new DOMParser(); xml = tmp.parseFromString( data , "text/xml" ); } else { // IE xml = new ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }, //空函数,开发插件的时候,可以作为回调函数的默认值,如果没有提供回调函数,则执行jQuery.noop() noop: function() {}, // 用于在全局作用域中执行javaScript代码 globalEval: function( data ) { if ( data && rnotwhite.test( data ) ) { // execScript()在全局作用域中按照指定的脚本语言执行脚本代码,默认语言是Jscirpt,没有返回值 //如果支持方法execScript(),则执行execScript(data);否则创建一个自调用匿名函数,在函数内部执行 ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // 转换连接字符式的字符串为驼峰式,用于CSS模块和数据缓存模块 // rdashAlpha = /-([a-z]|[0-9])/ig, // rmsPrefix = /^-ms-/, camelCase: function( string ) { //先用正则rmsPrefix匹配前缀"-ms-",如果有则修正为"ms-",然后用正则rdashAlpha匹配连字符"-"和其后的第一个字母或数字,并用字符串方法replace()和函数fcamelCase()把匹配部分替换为对应的大写字母或数字 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, //用于检查DOM元素的节点名称,与指定的值是否相等,检查时忽略大小写 nodeName: function( elem, name ) { //把属性elem.nodeName和参数name转换为大写再做比较,在执行elem.nodeName.toUpperCase()前先检测elem.nodeName是否存在,避免参数elem不是dom元素,或者elem没有属性nodeName导致错误 return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { //省略... }, // 移除字符串开头和结尾的空白符 //rnotwhite = /\S/, // trimLeft = /^\s+/, // trimRight = /\s+$/, // trim = String.prototype.trim trim: trim ? function( text ) { //如果传入的参数是null或undefined,则返回空字符串 //支持String.prototype.trim()则借用此方法 return text == null ? "" : trim.call( text ); } : // 不支持,则先调用方法toString()得到参数text的字符串表示,然后用正则trimLeft和trimRight匹配到的空白符替换为空字符串 function( text ) { return text == null ? "" : text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); }, // 将一个类数组对象转换成真正的数组 // array:待转换对象,可以是任何类型 //results:仅在jQuery内部使用,如果传入参数results,则在该参数上添加元素 makeArray: function( array, results ) { var ret = results || []; //定义返回值 if ( array != null ) { var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { //array没有属性,array是字符串,array是函数,是window对象,是正则对象,满足一个则断定参数array不是数组 //插入元素时执行的是push.call(ret,array),这是因为返回值ret不一定是真正的数组。如果只传入参数array,则返回值ret是真正的数组,如果还传入的第二个参数ret,则返回值ret的类型取决于该参数的类型 push.call( ret, array ); } else { //参数array是数组或类数组对象,调用jQuery.merge()把该参数合并到返回的值ret中 jQuery.merge( ret, array ); } } return ret; }, //在数组中查找指定元素的并返回其下标 // elem: 要查找的值 //array:数组,将被遍历的数组,来查找参数value在其中的下标 //i: 指定开始查找的位置,默认是0 inArray: function( elem, array, i ) { var len; if ( array ) { //如果支持数组方法indexOf(),则调用它并返回下标 if ( indexOf ) { return indexOf.call( array, elem, i ); } len = array.length; //修正参数i,若没指定参数i,则初始化为0,如果小于0,则加上数组长度,即从数组末尾开始计算,Math.max()方法在0与len+i之间取最大值,如果len+i仍然小于0,则把i修正为0 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { // Skip accessing in sparse arrays if ( i in array && array[ i ] === elem ) { return i; } } } return -1; }, //合并两个数组到第一个数组,第一个数组将会被改变 //first: 数组或类数组对象,必须含有整型属性length //second: 数组、类数组对象或任何含有连续整型属性的对象,其中的元素会被合并到第一个参数first中 merge: function( first, second ) { var i = first.length, j = 0; //判断second的length是否是数值类型 if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { //second没有属性length,则把该参数当作含有连续整型属性的对象,把其中的非undefined元素逐个插入参数first中 while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } //手动修正first的length first.length = i; return first; //返回修改后的first数组 }, //用于查找数组中满足过滤函数的元素,原数组不会受影响 //array:待遍历的数组 //callback: 过滤每个元素的函数,执行时被传入两个参数:当前元素和它的下标,返回一个布尔值 grep: function( elems, callback, inv ) { var ret = [], retVal; inv = !!inv; // 遍历数组,为每个元素执行过滤函数,如果inv为true,把执行结果false的元素放入结果数组ret中, // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { //省略 }, // 全局计数器,用于jQuery事件模块和缓存模块, guid: 1, //接受一个函数返回一个新的函数,新函数总是持有特定的上下文 proxy: function( fn, context ) { //如果参数context是字符串,说明参数格式是jQuery.proxy(context,name),修正为jQuery.proxy(fn,context) if ( typeof context === "string" ) { var tmp = fn[ context ]; context = fn; fn = tmp; } // 如果fn不是函数,则返回undefined if ( !jQuery.isFunction( fn ) ) { return undefined; } // 收集多余参数,借用数组的slice()方法 var args = slice.call( arguments, 2 ), proxy = function() { return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; // 为代理函数设置与原始函数相同的唯一标识guid,如果原始函数没有,则重新分配一个 proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; //返回创建的代码函数 return proxy; }, //获取当前时间 now: function() { return ( new Date() ).getTime(); }, // 浏览器嗅探 uaMatch: function( ua ) { ua = ua.toLowerCase(); var match = rwebkit.exec( ua ) || ropera.exec( ua ) || rmsie.exec( ua ) || ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || []; return { browser: match[1] || "", version: match[2] || "0" }; }, sub: function() { function jQuerySub( selector, context ) { return new jQuerySub.fn.init( selector, context ); } jQuery.extend( true, jQuerySub, this ); jQuerySub.superclass = this; jQuerySub.fn = jQuerySub.prototype = this(); jQuerySub.fn.constructor = jQuerySub; jQuerySub.sub = this.sub; jQuerySub.fn.init = function init( selector, context ) { if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { context = jQuerySub( context ); } return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; jQuerySub.fn.init.prototype = jQuerySub.fn; var rootjQuerySub = jQuerySub(document); return jQuerySub; }, browser: {} })
// 对象class2type jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); });
函数fcamelCase ()负责把连字符后的字母转换成为大写并返回
fcamelCase = function( all, letter ) { return ( letter + "" ).toUpperCase(); }
相关文章推荐
- jQuery源码研究分析学习笔记-jQuery原型属性和方法(九)
- jQuery源码研究分析学习笔记-jQuery.fn.init()(五)
- jQuery源码研究分析学习笔记-jQuery.extend()、jQuery.fn.extend()(八)
- jQuery源码研究分析学习笔记-回调函数(11)
- jQuery源码分析研究学习笔记-jQuery.clean()(七)
- jQuery源码研究分析学习笔记-jQuery.buildFragment()(六)
- jQuery源码研究分析学习笔记-jQuery.deferred()(12)
- C++学习笔记4--静态属性 静态方法 虚方法 抽象方法 多态性 析构函数 运算符重载 多继承 虚继承
- 静态方法与实例方法共享设计-jquery学习笔记
- jQuery源码分析9--静态与实例方法共享设计
- jQuery静态方法parseXML使用和源码分析
- Ext学习笔记01 - NameSpace,类实例属性,类实例方法,类静态方法
- 【C++】【学习笔记】【021-022】静态属性和静态方法
- jQuery源码学习10——和事件相关的方法
- C++学习笔记->静态属性和静态方法
- 2015.03.10,学习,文献笔记-“水轮机压力脉动的混频幅值置信度分析方法研究” (1)
- jQuery源码学习之三 (jQUery对象的实例属性和方法)
- jQuery源码分析10--方法链式调用的实现
- Javascript笔记:(实践篇)从jQuery插件技术说起-分析extend方法的源码(发现extend方法里有bug)(下篇)