了解前端的原型对象和原型链

65 阅读3分钟

前言

第一次尝试理解原型链的时候,感觉跟研究嵌套了几十层if-else的代码一样难受,不知道为啥js要用原型对象和原型链,不理解原型链的机制。

只能慢慢摸索了。。。

原型对象来源

javascript在最初时并没有类和继承这种概念,主要通过对象字面量和函数来实现面向对象编程。显然,仅用对象字面量和函数实现继承缺陷太大,所以需要引入新的概念弥补缺陷。

java、C++等都是基于类的面向对象编程语言,但是除了基于类的面向对象编程,还有基于原型对象的面向对象编程语言,如Self。

考虑到与基于类的面向对象相比,基于原型的面向对象编程具有动态性和高效性,所以js的原型对象概念可能就是借鉴的Self语言。

js引入原型对象后最简单的实践实现代码复用。

不使用原型对象的代码复用

函数是一种特殊对象,可以使用this关键字为该对象定义属性、方法。

function Person() {
  this.name = "Alice";
  this.age = 30;
}
const person = new Person();
console.log(person.name); // 输出: Alice

如果不考虑原型对象,应该如何实现代码复用呢?

如下图,此时有一个函数Person,要对Person进行实例化,要保证每个new出来的对象都有run方法,只能在Person内部使用this定义。于是,就有一个问题,person1、person2内的run方法都是创建对象过程中重新定义的,这样就会占用更多的内存,影响性能。

image.png

使用原型对象的代码复用

要解决上面的问题,就需要一个共享空间(对象)。

引入原型对象后,当我们定义一个函数A,除了创建函数对象本身外,还创建一个原型对象,并在函数对象内定义一个属性prototype,令该属性指向原型对象,这样就拥有了一个可以访问的共享空间。(原型对象还有一个属性constructor,指向该函数)。

当我们使用new关键字创建对象时: 1、生成一个空对象a,为对象定义属性[[Prototype]],令其指向函数的prototype(函数的原型对象) 2、将函数内this指向该空对象 3、执行函数代码,为新对象添加属性和方法。 4、返回新对象

image.png 有了原型对象,就可以把需要复用的属性和方法定义在原型对象中,通过链式访问[[Prototype]],就能共享属性或者方法。

原型链

通常,我们定义一个对象,有两个常用方法,通过字面量定义(即{})和new Object(),实际上通过字面量定义也需要调用new Object();

上面讲到,我们定义函数的时候会同时创建一个对象(原型对象),那该原型对象必然是通过new Object()生成的,那个生成的原型对象的[[Prototype]]属性也必然指向Object的原型对象,于是,形成了一条原型链。

Object的原型对象(也就是原型链的源头)是什么呢?Object的原型对象是js引擎内置的,包含许多对象的默认行为。

image.png

image.png

实现继承

待更新...