JavaScript里任何东西都是对象,任何一个对象内部(null除外)都有另一个对象叫__proto__
,即原型,它可以包含任何东西让对象继承。当然__proto__
本身也是一个对象,它自己也有自己的__proto__
,这样一级一级向上,就构成了一个__proto__
链,即原型链。当然原型链不会无限向上,它有个终点,可以称为原型链的顶端,或者root,它是一个特殊的对象,它的__proto__
为null。
obj.__proto__.__proto__......__proto__ === null;
但是对象并不是凭空产生的,它一般是某一个class
,或者确切说是构造函数的实例。JavaScript和其它面向对象的语言不太一样,Es6之前,它没有所谓的class
,而是用函数来模拟class
。定义了一个函数,实际上就定义了一个class
,函数本身就是class的constructor,例如:
// Person函数是Function对象的一个实例
function Person() {
}
// new Person()返回来的是一个对象,它是Object的一个实例,是没有继承Function的
var p = new Person();
这里创建了一个对象p
,是Person
的一个实例。既然p
是一个对象,它就有原型__proto__
,那p
的__proto__
是怎么设定的?这里就引出了prototype
,它是函数才有的一个属性,也是一个对象,一个函数创建的实例的__proto__
就指向这个函数的prototype
。所以p
的__proto__
被设定为Person.prototype
,即:
p.__proto__ === Person.prototype
// 实例对象原型的值为其对应构造函数显式原型的值即prototype的值
当然Person.prototype
也是个对象,它自然也有__proto__
,默认指向Object.prototype
,即:
Person.prototype.__proto__ === Object.prototype
而Object.prototype
已经没有原型了,它的__proto__
是null
。
以上就构成了由对象p
开始的原型链:
p.__proto__ === Person.prototype
p.__proto__.____proto__ === Object.prototype
JavaScript因此而推断出:
p instanceof Person=== true;
p instanceof Object === true;
注意,这就是JavaScript判断一个对象是否instanceof
某个函数的依据,即对象p
的原型链上有没有一个__proto__
是这个函数的prototype
,如果有,那么p
就是这个函数的instance
。由于一般所有的原型链最终都会指向顶端的Object.prototype
,所以它们都是Object
的instance
。
实现instance
/*A 表示左表达式,B 表示右表达式
A instanceof B
如果B的显式原型在A的原型链上,返回true*/
function instance_of(A, B) {
let R = B.prototype; // 取 B 的显示原型
A = A.__proto__;// 取 A 的隐式原型
// A的 __proto__ 是不是强等于 B.prototype,不等于再找 A.__proto__ .__proto__ 直到 __proto__ 为 null
while (true) {
if (A === null) return false;
if (R === A) return true;
A = A.__proto__;
}
}
Function和Object的关系
一般任何对象都是Object的instance,因为原型链的顶端都指向Object.prototype
。那么Object本身是什么?Object
也是个函数,而任何函数都是Function
的实例对象,比如Array,String,当然Object也包括在内,它也是Function的实例,即:
// 首先Object和Function都是构造函数,而所有的构造函数的都是Function的实例对象. 因此Object是Function的实例对象
Object.__proto__ === Function.prototype;
Function.__proto__ === Function.prototype
Object instanceof Function === true
同时,Function
是个对象,它的原型是Function.__proto__
,指向Function.prototype
,并且这个原型链向上继续指向Object.prototype
,即:
// Function.prototype是Object的实例对象 实例对象的原型会指向其构造函数的prototype属性
Function.prototype.__proto__ === Object.prototype
Function.__proto__.__proto__ === Object.prototype;
Function instanceof Object === true
这样就有了一个JavaScript里经常说到的蛋鸡问题:
Object instanceof Function === true
Function instanceof Object === true
“先鸡先蛋?”
总结
- 每个对象都具有一个名为__proto__的属性
- 每个构造函数都具有一个名为prototype的方法 ,所以prototype同样带有__proto__属性
- 首先Object和Function都是构造函数,而所有的构造函数的都是Function的实例对象. 因此Object是Function的实例对象
- Function.prototype是Object的实例对象
- 当我们访问一个属性值的时候, 它会沿着原型链向上查找, 直到找到或者到
Object.prototype.__proto__
(为null)截止.
讲在后面
Function.prototype.a = 'a';
Object.prototype.b = 'b';
// Person函数才是Function对象的一个实例
function Person() {
}
// new Person()返回来的是一个对象,它是Object的一个实例,是没有继承Function的
var p = new Person();
/* p.__proto__ === Person.prototype
Person.prototype.__proto__ === Object.prototype
p.__proto__.____proto__ === Object.prototype*/
console.log('p.a: ' + p.a);
// 自身找,没有 ==> 到原型上找(p.__proto__(Person.prototype)) 没有 ==> 到Person.prototype.__proto__(Object.prototype) 没有 undefined
console.log('p.b: ' + p.b);
// 自身找,没有 ==> 到原型上找(p.__proto__(Person.prototype)) 没有 ==> 到Person.prototype.__proto__(Object.prototype) 找到b
// Person函数才是Function对象的一个实例
console.log('Person.a: ' + Person.a);
// 自身找,没有 ==> 到原型上找(Person.__proto__(Function.prototype)) 找到 a
// js里面所有对象都是Object的实例 Person函数可以访问到Object原型里面的属性
console.log('Person.b: ' + Person.b);
// 自身找,没有 ==> 到原型上找(Person.__proto__(Function.prototype)) 没有,==> 到 Function.prototype.__proto__ === Object.prototype,找到b
var foo = {},
F = function () {
};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';
console.log(foo.a);
// 自身找,没有 ==> 到原型上找(foo.__proto__(Object.prototype)),找到value a
console.log(foo.b);
// 自身找,没有 ==> 到原型上找(foo.__proto__(Object.prototype)),没有 ==> 到foo.__proto__.__proto__ (Object.prototype.__proto__): 没有 undefined
console.log(F.a);
// 自身找,没有 ==> 到原型上找(F.__proto__(Function.prototype)), 没有 ==> 到F.__proto__.__proto__(Object.prototype): 找到value a
console.log(F.b);
// 自身找,没有 ==> 到原型上找(F.__proto__(Function.prototype)),找到value b