前言
- 细阅此文章大概需要 左右
- 本篇中讲述了:
-
- JQuery源码中关于数据类型检测的部分
-
- 如果有任何问题都可以留言给我,我看到了就会回复,如果我解决不了也可以一起探讨、学习。如果认为有任何错误都还请您不吝赐教,帮我指正,在下万分感谢。希望今后能和大家共同学习、进步。
- 下一篇会尽快更新,已经写好的文章也会在今后随着理解加深或者加入一些图解而断断续续的进行修改。
- 如果觉得这篇文章对您有帮助,还请点个赞支持一下,谢谢大家!
JQuery源码中的数据类型检测
var class2type = {};//创建一个空对象//后面被创建为一个映射表
var toString = class2type.toString;//=>Object.prototype.toString
var hasOwn = class2type.hasOwnProperty;//=>Object.prototype.hasOwnProperty
var fnToString = hasOwn.toString;//=>Object.prototype.hasOwnProperty.toString
var ObjectFunctionString = fnToString.call( Object );
////=>Object.prototype.hasOwnProperty.toString.call( Object )
// Populate the class2type map
//相当于用forEach将所有这些数据类型按空格分割放到数组中。
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( _i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );
//然后以某种特定的形式,封装到对象中,作为一个映射表使用、
/* 形成的映射表
{
[object Object]:object,
[object Array]:array,
[object String]:String,
[object Date]:date,
[object Number]:number,
[object Boolean]:boolean,
[object RegExp]:regexp,
[object Function]:function,
[object Error]:error,
[object Symbol]:Symbol
}
*/
//【检测是不是函数】
//如果是函数则使用typeof进行判断,是函数且不是节点对象【节点对象使用typeof进行判断时也会被认为是函数】
var isFunction = function isFunction( obj ) {
// Support: Chrome <=57, Firefox <=52
// In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`).
// We don't want to classify *any* DOM node as a function.
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
//【判断是不是window【且不为空】】,基于window自带属性(window.window === window),
var isWindow = function isWindow( obj ) {
return obj != null && obj === obj.window;
};
//【toType:大的数据类型检测】进行数据类型判断
function toType( obj ) {
//若为空,直接返回空【字符串类型】
if ( obj == null ) {
return obj + "";
}
// Support: Android <=2.3 only (functionish RegExp)
//三元运算符,若条件符合,则是对对象或函数进行判断【对应映射表】,若不是则是对基本数据类型直接使用typeof进行判断
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
}
//【isArrayLike:判断是数组还是类数组】
function isArrayLike( obj ) {
// Support: real iOS 8.2 only (not reproducible in simulator)
// `in` check used to prevent JIT error (gh-2145)
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
//
//length赋值为false或【数组或类数组的长度】
//type赋值为传入参数的数据类型
var length = !!obj && "length" in obj && obj.length,
type = toType( obj );
//如果是函数或window直接返回false
if ( isFunction( obj ) || isWindow( obj ) ) {
return false;
}
//1.若数据类型为array则返回true
//2.若长度为0的类数组返回true
//3.若【长度不为零】且【长度大于零】且【长度减一包含在obj当中】,都满足返回true
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
//但是有一种情况也会被认为是类数组
//{4:100,length:5}//实际上不是数组或类数组,但是由于最后的判断,会被JQuery认为是数组
}
//【isEmptyObject:检测是否为空对象】
//若能用forin循环遍历对象中的每一项,则就不是一个空对象
//其实里面还可以进行一个处理,如果是一个object才能进行循环,如果连个对象都不是,则结果不一定准确,
//进去可以先加一个判断,看看是不是一个对象
function isEmptyObject( obj ) {
var name;
//保证是一个对象,若obj不存在,或不是一个对象,直接false
if ( !obj || toType(obj)!=='object') {
return false;
}
for ( name in obj ) {
//再判断一下,属性是不是私有的,遍历到原型上的公有属性,则意味着私有的已经遍历完了 ,直接break
//因为所有的遍历都是先找私有的,私有的找不到了,才上公有上找
if(!hasOwn.call(obj,name)) break;
return false;
}
//如果进来了直接break了,则直接返回true
return true;
}
//【isPlainObject:检测是否为纯粹对象】
//原型链指向的直接所属的原型一定是Object.protopype,{}这种是纯粹对象
var getProto = Object.getPrototypeOf;//获取原型
function isPlainObject( obj ) {
var proto, Ctor;
// Detect obvious negatives
// Use toString instead of jQuery.type to catch host objects
//若不存在或不是对象,则直接返回false
if ( !obj || toString.call( obj ) !== "[object Object]") {//||后面可简写为toType(obj)!=='object'
return false;
}
proto = getProto( obj );//获取obj所属类的原型
// Objects with no prototype (e.g., `Object.create( null )`) are plain
//【只有这种情况】如果没有原型链的
//例如在使用Object.create( null )时,传入null,则创建出来的实例没有原型链指向
//则认为其是个纯粹的对象
if ( !proto ) {
return true;
}
// Objects with prototype are plain iff they were constructed by a global Object function
//若找到原型了,就看看原型上有没有constructor如果有就获得【constructor值】,如果用hasOwn没有,就返回false
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;//相当于fnToString.call( Ctor )==fnToString.call( Object )要检测的和Object进行比较,若成立则认为【被检测的直接所属的原型链一定是Object.protopype】为一个对象
}