初探原型与原型链

73 阅读3分钟

前言

本来是打算写map、set、weakmap、set的区别的,学着学着就学到了原型和原型链,记录一波

原型

看了不少关于原型的描述,每个实例对象都会有个私有属性__proto__称为隐式原型,当实例对象是继承或者通过构造函数new出来的时,这个实例对象不仅拥有隐式原型也拥有显式原型(prototype)。

  • 私有属性称之为__proto__(隐式原型)
  • 原型对象(prototype)(显式原型)

例子

  1. 为了让大家对原型有个更为直观的了解,写几行代码意思一下
const oneHundredObjects = {};
console.log(oneHundredObjects.__proto__);
console.log(oneHundredObjects.prototype);

image.png

通过运行代码可以发现此时的对象拥有__proto__这个私有属性(隐式原型),没有prototype(显式原型)

  1. 接下来让我们创建个函数看看
function twoHundredObjectsFun() {}
console.log(twoHundredObjectsFun.__proto__);
console.log(twoHundredObjectsFun.prototype);

image.png

此刻可以发现函数同时拥有__proto__隐式原型和prototype显示原型

  1. 接下来我们通过new操作符创建一个对象来看看,其实就是通过new一个普通函数(构造器),此时也可以称之为构造函数
function twoHundredObjectsFun() {}
twoHundredObjectsFun.prototype.name = 'xiaoxiao';

const xiaoxiao = new twoHundredObjectsFun();
console.log(xiaoxiao.__proto__);
console.log(twoHundredObjectsFun.prototype);

image.png

image.png 这时我们会发现实例对象的隐式原型和函数的显示原型他们指向的是同一个地址。同时我们展开发现显示原型和隐式原型都是一个对象,并且也都拥有_proto__私有属性。

  1. 接下来我们再将更深一层的隐式原型打印一下看看
function twoHundredObjectsFun() {}
twoHundredObjectsFun.prototype.name = 'xiaoxiao';

const xiaoxiao = new twoHundredObjectsFun();
console.log(xiaoxiao.__proto__.__proto__);
console.log(twoHundredObjectsFun.prototype.__proto__);

image.png

小结

  1. 实例对象拥有隐式原型,它的构造函数同时拥有显式原型和隐式原型
  2. 通过new操作符创建的实例对象的__proto__(隐式原型)指向它的构造函数的(prototype)显示原型
  3. 实例对象的显示原型和隐式原型还会继续的往下继续寻找隐式原型,直到__proto__为null,然后继续的话会报错

原型链

通过对原型的探索,发现了每个实例对象都有一个私有属性(隐式原型),并且它的指向是它的构造函数的prototype(显式原型),并且这个显式原型也拥有一个私有属性(隐式原型),这样层层递进,最终__proto__(隐式原型)为null时停止,将__proto__一级一级的链接起来就是为原型链

constructor

在Javascript语言中,constructor属性是专门为function而设计的,它既存在__proto__隐式原型中也存在显式原型中。这个constructor保存了指向function的一个引用。

const chenchen = {};
function twoHundredObjectsFun() {}
twoHundredObjectsFun.prototype.name = 'xiaoxiao';

const xiaoxiao = new twoHundredObjectsFun();
console.log(xiaoxiao.__proto__);
console.log(twoHundredObjectsFun.prototype);
console.log(chenchen.__proto__);

image.png 通过运行代码可知,当我们打印,我们发现chenchen对象虽然没有继承和通过构造函数创建,但是它也默认生成了属性constructor,对应Object构造函数,而xiaoxiao这个通过new操作符生成的实例对象,它也有一个属性constructor,对应的构造函数本身

小结

  1. constructor属性无论在对象实例的proto还是构造函数的prototype中都存在
  2. 没有继承或者是没有通过new操作符构建的对象,它的对象实例中的constructor属性指向的是默认的Object构造函数
  3. 构造函数的原型对象prototype的constructor属性,生成一个指向当前构造函数的指针,默认引用的是构造函数本身。