jQuery源码阅读4-2:类型判断isPlainObject()方法

isPlainObject这个方法比较深, 因为对象的组合方式太灵活了 , 原型链我理解也不到位(下篇博文一定得学习一下), 兼容性有关的东西又太多了, 而且”纯对象”这东西太抽象
这篇博客里存疑比较多 , 先把能看懂的星系简单记一下, 以后返工是肯定的了…

从这个函数学到好些东西:
1.DOMObj.nodeType : Dom对象才有这个属性(IE低版本里没有), 比如说body是1
2.for in 遍历的顺序 : 结论是先遍历父类属性, 后遍历子类属性
3.hasOwnProperty只查询实例的属性, isPrototypeOf会查询原型链上constructor的指向(可以查询多层)

一:测试示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//举个"寄生组合"式继承的例子<<js高程>>推荐的方式
//父类
function Person(name) {
this.NOTE = "Person自带属性";
this.PER_NOTE = "Person属性,不让覆盖的";
this.name = name;
this.funPerson = function(){
return this.NOTE+this.name;
};
}
//子类
function Student(name,age) {
Person.apply(this,arguments);//1.借用构造函数继承
this.NOTE = "Student自带属性,会重写父类的NOTE";
this.STU_NOTE = "Student自带属性";
this.age=age;
this.funStudent = function(){
return this.NOTE+this.age;
};
}
Student.prototype = new Person();//2.原型继承
Student.prototype.constructor = Person;//3.组合继承
//子类实例
var stu = new Student("ruantao.duapp.com",25);

二:源码

二.1:for in遍历顺序问题

1
2
3
4
5
6
7
8
9
10
/**
* 博文作者:ruantao1989@gmail.com
* 引自博客:ruantao.duapp.com/blog
*/
//1.for in遍历顺序问题:
//各个浏览器都会先遍历父类的属性, 之后再遍历子类的属性
for ( key in stu ) {
console.log(key);
}
console.log("==>最终key值:"+key);

二.2:用hasOwnProperty检测实例属性

1
2
3
4
5
6
7
8
9
//用call继承而来的对象里 会有父类的属性和方法, 所以下一组测试全是true
console.log("实例属性==>"+stu.hasOwnProperty("STU_NOTE"));//true 自身的属性像age什么的一样
console.log("实例方法==>"+stu.hasOwnProperty("funStudent"));//true
console.log("实例继承属性==>"+stu.hasOwnProperty("PER_NOTE"));//true
console.log("实例继承方法==>"+stu.hasOwnProperty("funPerson"));//true
//原型链上,父类的方法就返回false
console.log("原型链中的方法==>"+stu.hasOwnProperty("toString"));//false
//Student的prototype没指定, 是空的, 拿什么判断都是false
console.log(Student.prototype.hasOwnProperty("STU_NOTE"));//false

二.3:用isPrototypeOf检查原型链上的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
Student.prototype.isPrototypeOf(stu);//true
//这个返回false, 因为用call继承的话, stu的constructor指向Student,Student指向Object
Person.prototype.isPrototypeOf(stu);//false
//下边这俩能体现链上多层constructor的指向
Object.prototype.isPrototypeOf(stu);//true
Object.prototype.isPrototypeOf(Student);//true
//new出来的可以检测到
var newStr = new String("newStr");
String.prototype.isPrototypeOf(newStr);
//不是new出来的就检测不到
var writeStr = "newStr";
String.prototype.isPrototypeOf(writeStr);

三: 存疑很多的源码阅读…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//==>源码38行
//缓存hasOwnProperty
core_hasOwn = Object.prototype.hasOwnProperty,
//==>源码439行
isPlainObject: function( obj ) {
//如果obj.nodeType有值, 就是DOM对象(非IE中, nodeType对应一组常量)
//window对象也不算, 特殊判断了一下
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
try {
//对象都是构造出来的,都有constructor: 比如"" -> String -> Function -> Function
//obj.hasOwnProperty("constructor")和obj.constructor.prototype.hasOwnProperty("isPrototypeOf")用于检查组合继承和原型继承
//js继承大概分prototype , call/apply, 还有组合使用几种
//这块我理解很不到位, 具体原理不太清楚
if ( obj.constructor &&
!core_hasOwn.call(obj, "constructor") &&
!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
} catch ( e ) {
// IE8,9有可能会报异常, 我没遇上...
return false;
}
//先遍历父类属性, 后遍历子类属性, 只保留最后一个
var key;
for ( key in obj ) {}
//传入{}时key === undefined, 但obj.hasOwnProperty(key)为true;
return key === undefined || core_hasOwn.call( obj, key );
},
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
//能进到循环, 证明就有属性
return false;
}
return true;
},