JS 原型、原型链,不再傻傻分不清楚,一文彻底读懂原型链

原型链图

image

图很重要!图很重要!图很重要!强烈建议让图片置顶起来,结合图片阅读下去。

普通对象与函数对象

JS 中的对象分为 普通对象函数对象

类型 属性 例子 对应上面的图
普通对象 __proto__ {}、new 实例 f1、f2、o1、o2、x.prototype
函数对象 __proto__ 以及 prototype ObjectFunctionRegExp Foo、Object、Function

__proto__prototype 的作用

属性 作用
__proto__ 内含属性 constructor__proto__
prototype 默认有 constructor 属性,用于记录实例是由哪个构造函数创建

准则

  1. 原型对象的 constructor 指向构造函数本身
  2. 实例的 __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 属性

image

p3 属性

image

p1 没有 .constructor 属性,所以它沿者 [[Prototype]] 链向上委托到了 person.prototype。但是这个对象也没有 .constructor,因为在实例化之前 person.prototype 指向了另一个函数。

所以它继续委托,这次轮到了 Object.prototype,委托链的最顶端。那个 对象上确实拥有 .constructor,它指向内建的 Object(..) 函数。

总结

  1. 所有对象的 __proto__ 最终指向 Object.prototype,而 Object.prototype__proto__ 指向 null
    • x.__proto__.[__proto__.] === Object.prototype
    • Object.prototype === null
  2. 实例的 __proto__ 指向其构造函数的原型对象 X.prototype
    • x.__proto__ === X.prototype
  3. 原型对象也是普通对象
posted @ 2021-07-02 11:18  to人间值得  阅读(127)  评论(0编辑  收藏  举报