菜鸟前端的进阶之路(一)

129 阅读3分钟

原型、原型链和构造函数的关系

对于前端开发人员都知道构造函数,并且构造函数有一个prototype属性,第一天探究prototype属性

prototype

首先创造一个构造函数

function Person() {}                 // 创建一个人的构造函数
Person.prototype.color = 'yellow';   // 该构造函数的prototype添加一个肤色的属性
const person1 = new Person();        // 实例化两个人的对象
const person2 = new Person();

console.log(person1.color);         // yellow
console.log(person2.color);         // yellow

从代码中可以看出我并没有给实例化人的对象添加肤色的属性但是却可以打印出人的肤色‘yellow’,看代码可以猜出肯定跟prototype这个神秘的属性有关,因为前面给prototype添加了肤色的属性。

那么prototype是什么东西呢?指向什么?

prototype其实是指向通过构造函数的原型所创建出来的对象的原型,也就是上面的 person1 和 person2的原型。

    Person(构造函数的prototype) --> Person.prototype(实例原型)。

那么问题又来了原型又是什么东西呢?又如何证明上一句话的正确性。 js每个对象在创建时都会有一个原型对象,可以从该对象的原型对象上继承所有的属性和方法(Object.create()可以创建一个空的原型对象或指定原型对象)。

console.log(Person.prototype === person1.__proto__);  // true

每个对象上都会有一个__proto__属性,该属性就是指向该对象的原型对象。所以上述代码为true就证明了上面话的正确性。这也是为什么 peroon1 和 person2 会有肤色“color”属性的原因。

    Person(构造函数的prototype) --> Person.prototype(实例原型)。
    person1的__proto__ --> Person.prototype(实例原型)。

既然上面说到每个对象都有一个原型对象,那么实例原型也是一个对象那他也应该也有一个原型对象吧。怀着好奇的心情必须得看一下。

    console.log(Person.prototype.__proto__); 
    // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ} 
    // 打印的是Object顶级对象了

实例原型指向的是顶级对象Object。既然是顶级对象,那也是对象,那必须套娃看看顶级对象上面还有没有更顶级的对象。

    console.log(Person.prototype.__proto__.__proto__);  // null

顶级对象的原型对象打印的是null,证明顶级对象确实是顶级对象,它上面也没有了更顶级的对象,也可以说顶级对象的原型为空。

原型链

其实上面通过对象向上查找其实就引出了原型链。通过对象的原型属性所关联的对象,原型对象一层一层的向上查找一直到顶级对象停止。这就是一条原型链。

constructor

最后补充一下constructor属性,每个原型上都会有一个constructor属性,该属性的指向的是与之相关的构造函数。

     console.log(Person === Person.prototype.constructor); // true
   

所以constructor其实就是构造函数。

总结

通过上面的分析:构造函数的prototype指向的是实例原型。实例对象的原型也是指向的实例原型。实例原型的constructor又指回构造函数。原型的原型指向顶层对象。