JavaScript原型链

94 阅读3分钟

前言:

先说几个结论,方便理解:

  1. 每个对象都有一个属性叫__proto__指向其构造函数的prototype。
  2. prototype本身也是一个对象,所以他也有__proto__属性。
  3. 每个函数(构造函数)都有一个prototype对象。
  4. 原型链的终点(底部)是Object.prototye.__proto__ === null。
  5. 构造函数的prototype的constructor指向函数自己。

知道了以上几点,理解原型和原型链就比较简单了。

认识对象的原型

Javascript中每个对象都有一个属性__proto__,这个属性指向另一个对象(prototye)。

那么这个属性有什么用呢?

当我们通过引用对象的属性key来获取一个value时,它会触发 [[Get]]的操作;

这个操作会首先检查该属性是否有对应的属性,如果有的话就使用它;

如果对象中没有该属性,那么会属性__proto__指向的对象上的属性;

如何获取prototype这个对象呢?

方式一:通过对象的 __proto__ 属性可以获取到(但是这个是早期浏览器自己添加的,存在一定的兼容性问 题);

方式二:通过 Object.getPrototypeOf 方法可以获取到;

函数的原型prototype

每个函数都有其对应的prototype

function foo(){}
console.log(foo.prototype)

对象没有

let obj = {}
obj.prototype //对象没有这个属性

通过构造函数创建一个对象实例的内存表现

function Person(){};

let person1 = new Person();
let person1 = new Person();
\\相当于会执行以下操作
p = {};
p.__proto__ = Person.prototype;
\\
console.log(person1.__proto__ === Person.prototype); //true
console.log(person1.__proto__ === person2.__proto__); //true

内存表现:

image.png

原型继承关系#

image.png

关于面试:

原型链是什么:

涉及到的概念挺多的,先举例说明:

假设有一个普通对象x={},这个x会有一个隐藏属性__proto__,这个属性会指向Object.prototype。 即

x.__proto__===Object.prototypex.\_\_proto\_\_=== Object.prototype

此时,我们说x的原型是Object.prototype。而__proto__属性的唯一作用就是用来指向x的原型。

接下来说说原型链,还是举例说明:

假设有一个数组对象a =[],这个a也有一个隐藏属性叫__proto__,这个属性会指向Array.prototype。Array.prototype也有一个隐藏属性__proto__,指向Object.prototype。即

a.__proto__===Array.prototypea.\_\_proto\_\_ === Array.prototype

此时我们说a的原型是Array.prototype,跟上面的x一样,但也有点不一样。那就是Array.prototype也有一个隐藏属性__proto__指向Object.prototype,即

Array.prototype.__proto__===Object.prototypeArray.prototype.\_\_proto\_\_ === Object.prototype

这样一来,a就有了两层原型,

  1. a的原型是Array.prototype
  2. a的原型的原型是Object.prototype

于是通过隐藏属性__proto__就形成了一个链条

a===>Array.prototype==>Object.prototypea===>Array.prototype==>Object.prototype

以上就是原型链

怎么改变原型链:

看来好像只要改写x的__proto__属性就可以改变x的原型

x.__proto__ = 原型

但是这个写法是并不推荐的,推荐的写法是

const x = Object.create(原型);
//或者
const x = new 构造函数() //会导致x.__proto__=构造函数.prototype

原型链解决了什么问题(有什么用)

在没有class的情况下实现继承,以上面的数组a为例:

  1. 我们说a是Array的实例, a拥有Array.prototype里面的属性。
  2. Array继承了Object
  3. a又是Object的间接实例,a拥有Object.prototype的属性

这样一来a既有了Array.prototype里的属性,又有了Object.prototype里的属性。

这种继承相比于class实现的继承存在的缺点是,不支持私有属性。

所以怎么解决这个问题呢?那就直接使用class实现继承吧

参考:www.zhihu.com/question/56…