JS 原型、原型链,不再傻傻分不清楚,一文彻底读懂原型链
原型链图
图很重要!图很重要!图很重要!强烈建议让图片置顶起来,结合图片阅读下去。
普通对象与函数对象
JS 中的对象分为 普通对象
和 函数对象
类型 | 属性 | 例子 | 对应上面的图 |
---|---|---|---|
普通对象 | __proto__ |
{}、new 实例 |
f1、f2、o1、o2、x.prototype |
函数对象 | __proto__ 以及 prototype |
Object 、Function 、RegExp 等 |
Foo、Object、Function |
__proto__
和 prototype
的作用
属性 | 作用 |
---|---|
__proto__ |
内含属性 constructor 和 __proto__ |
prototype |
默认有 constructor 属性,用于记录实例是由哪个构造函数创建 |
准则
- 原型对象的
constructor
指向构造函数本身 - 实例的
__proto__
(f1.__prototype__
) 和原型对象(Foo.prototype
)指向同一个地方
// function Foo()
function Foo(){}
var f1 = new Foo()
var f2 = new Foo()
f1.__proto__ === Foo.prototype // 准则 2
f2.__proto__ === Foo.prototype // 准则 2
Foo.prototype.__proto__ === Object.prototype // 准则 2 (Foo.prototype 原型对象也是普通的对象)
Object.prototype.__proto__ === null // 原型链结束
Foo.prototype.constructor === Foo // 准则 1
Foo.__proto__ === Function.prototype // 准则 2 (Foo 是 Function的实例)
// function Object()
var o1 = new Object()
var o2 = new Object()
o1.__proto__ === Object.prototype // 准则 2
o2.__proto__ === Object.prototype // 准则 2
Object.prototype.__proto__ === null // 原型链结束
Object.prototype.constructor === Object // 准则 1
Object.__proto__ === Function.prototype // 准则 2 (Object 是 Function的实例,这...)
Object.__proto__.__proto__ === Object.prototype // 准则 2 (Object.__proto__ 指向 Function.prototype)
// Function Function()
Function.__proto__ = Function.prototype // 准则 2 (自己是自己的实例,啊这...)
Function.prototype.constructor = Function; // 准则 1
Function.prototype.__proto__ === Object.prototype // 准则 2 (Function.prototype 原型对象也是普通的对象)
题目
接下来是实操演练了
function person() {
this.age = 10;
}
var p3 = new person()
person.prototype = {
age: 1,
getAge: function() {
console.log(this.age);
}
}
var p1 = new person();
var p2 = new person();
p1.getAge(); // 10 先找 person 本身的 age
p2.age = 12;
person.prototype.age = 15;
p2.getAge(); // 12
p3.getAge(); // Uncaught TypeError: p3.getAge is not a function
p3.constructor.prototype.getAge(); // 1,p3[.__proto__].constructor 就是 person
person.__proto__.age = 18; // person.__proto__ === Object.__proto__ === Function.prototype,这里可以认为修改的是 Object.age = 18 也可以是 Function.prototype.age = 18
p1.__proto__.getAge(); // 15 找原型链上的 person,即 person.prototype, p1.__proto__ === person.prototype
p1.__proto__.age = 20; // 即 person.prototype.age = 20
person.prototype.getAge(); //20
p1.constructor === person; // false, person 没有 constructor 属性,实例化前被改写了
p1.constructor === Object; // true, 沿着 [[Prototype]] 链,在 Object 找到 constructor 属性
p1.__proto__.constructor === Object // true
p3.constructor === person; // true, person 有 constructor 属性,实例化前没有被改写了
p3.constructor === Object; // false, 沿着 [[Prototype]] 链,在 Object 找到 constructor 属性
p3.__proto__.constructor === Object // false
p1 属性
p3 属性
p1
没有 .constructor
属性,所以它沿者 [[Prototype]]
链向上委托到了 person.prototype
。但是这个对象也没有 .constructor
,因为在实例化之前 person.prototype
指向了另一个函数。
所以它继续委托,这次轮到了 Object.prototype
,委托链的最顶端。那个 对象上确实拥有 .constructor
,它指向内建的 Object(..)
函数。
总结
- 所有对象的
__proto__
最终指向Object.prototype
,而Object.prototype
的__proto__
指向null
x.__proto__.[__proto__.] === Object.prototype
Object.prototype === null
- 实例的
__proto__
指向其构造函数的原型对象X.prototype
x.__proto__ === X.prototype
- 原型对象也是普通对象