jQuery 源码分析5: jQuery 基本静态方法(一)
jQuery在初始化过程中会为自己扩展一些基本的静态方法和属性,以下是jQuery 1.11.3版本 239 ~ 564行间所扩展的静态属性和方法
1 jQuery.extend({ 2 3 // 为每个jQuery拷贝建立一个唯一的编号 4 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 5 6 // 假设jQuery脱离模块支持,已经准备好 7 isReady: true, 8 9 // 空转函数 10 noop: function() {}, 11 12 /******************* 基本类型判断方法 *****************************/ 13 14 isFunction: function( obj ) { 15 return jQuery.type(obj) === "function"; 16 }, 17 isArray: Array.isArray || function( obj ) { 18 return jQuery.type(obj) === "array"; 19 }, 20 isWindow: function( obj ) { /* jshint eqeqeq: false */ 21 return obj != null && obj == obj.window; 22 }, 23 24 isNumeric: function( obj ) { 25 // 首先抛弃数组, 利用parseFloat返回一个浮点数 26 // 如果obj是一个合法数字(包括字符串数字),与parseFloat返回值的差是0,因此相减后等0,于是加1 27 // 如果obj是"0x10",返回值则是0,而obj - 0则会得到16,因此判断"0x10"也是数值 28 // 如果obj是"abc"等非法数字,会得到NaN - NaN,最终也会得到非数值的判断 29 30 return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0; 31 }, 32 // 保证obj不包含任何属性 33 isEmptyObject: function( obj ) { 34 var name; 35 for ( name in obj ) { 36 37 return false; 38 } 39 return true; 40 }, 41 // 最常使用的判断之一,纯对象判断 42 // 纯对象是有 new 或 {} 创建的对象 43 // 意味着纯对象不能从其他对象原型中继承而来,只能从Object原型中继承 44 isPlainObject: function( obj ) { 45 var key; 46 // 首先必须是一个object 47 // 针对IE,需要检查对象的constructor属性 48 // 把DOM节点和window对象都过滤掉 49 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { 50 return false; 51 } 52 try { 53 // Not own constructor property must be Object 54 if ( obj.constructor && // 不包含构造器 55 !hasOwn.call(obj, "constructor") && 56 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { 57 return false; 58 } 59 60 } catch ( e ) { 61 // IE8或9在某些主机上会抛出异常 62 return false; 63 } 64 // 支持: IE<9 65 // 先处理继承的属性,之后才会处理自身属性 66 if ( support.ownLast ) { 67 for ( key in obj ) { 68 return hasOwn.call( obj, key ); 69 } 70 } 71 // 一般浏览器是先遍历自己的属性,因此利用空变量来略过之前的自身属性,直接跳到最后一个属性 72 // 如果最后一个属性是自身的,那么证明了所有属性都是自身的 73 for ( key in obj ) {} 74 return key === undefined || hasOwn.call( obj, key ); 75 }, 76 77 78 79 /********************** 基本工具 **********************/ 80 81 type: function( obj ) { 82 if ( obj == null ) { 83 return obj + ""; // 返回一个字符串 'null' 84 } 85 86 // //jQuery初始化过程中会产生一个"class到type"的表 87 // jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { 88 // class2type[ "[object " + name + "]" ] = name.toLowerCase(); 89 // }); 90 // // 实际上class2type是这样的 91 // var class2type = { 92 // "[object Array]": "array", 93 // "[object Boolean]": "boolean", 94 // "[object Date]": "date", 95 // "[object Function]": "function", 96 // "[object Number]": "number", 97 // "[object Object]": "object", 98 // "[object RegExp]": "regexp", 99 // "[object String]": "string", 100 // "[object Error]" : "error", 101 // }; 102 // toString(123) 实际上会返回一个字符串"[object Number]",此时就可以通过class2type表来返回"number" 103 // type(123) 返回的就是"number" 104 // 这样做的原因是,对于很多对象,typeof返回的只是object,无法区分具体是什么对象 105 // 通过object.prototype.toString.call(obj),虽然可以判断出什么对象,但是返回值却不够简练,因此使用了class2type进行映射 106 return typeof obj === "object" || typeof obj === "function" ? 107 class2type[ toString.call(obj) ] || "object" : // 通过class2type来返回object类型 108 typeof obj; 109 }, 110 // Evaluates a script in a global context 111 // 在全局上下文上执行一个脚本 112 globalEval: function( data ) { 113 if ( data && jQuery.trim( data ) ) { 114 // IE上使用execScript 115 // 使用一个匿名函数,从而使上下文在firefox中变成window而非jQuery 116 ( window.execScript || function( data ) { 117 window[ "eval" ].call( window, data ); 118 } )( data ); 119 } 120 }, 121 // 转换 dashed to camelCase; CSS和数据模块才使用这个方法 122 // 首先要去除'-ms-'中的第一个'-' 123 // 然后删除'-'并将'-'后紧接着的字母转换成大写 124 // rmsPrefix = /^-ms-/ 125 // rdashAlpha = /-([\da-z])/gi 126 // fcamelCase = function( all, letter ) { 127 // return letter.toUpperCase(); 128 // }; 129 camelCase: function( string ) { 130 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 131 }, 132 // 判断elem节点的名字是否为name 133 // 在后面对节点的操作经常会用到 134 nodeName: function( elem, name ) { 135 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 136 }, 137 });
总结
- 基本判断方法里,jQuery.isNumeric的实现过程比较简练,要判断"0x10"这样的十六进制数字,又要判断"1.23"这样的浮点数.该方法里面只使用到了parseFloat,并根据其返回值的特点("字符串前部的合法数字"),只使用一次函数就可判别出数字,实现得非常精明;
- 纯对象的判断jQuery.isPlainObject也是用得较多的工具,其中针对浏览器的兼容性实现和优化都值得学习;
- jQuery.type的实现方案更加精彩,因此不同平台上typeof不一定能够准确返回对象的类型,因此需要使用到Object.ptototype.toString方法,然而这个方法会返回不需要的字符,建立一个映射表便可解决这一个问题;