概念理解
在理解原型链之前需要理解几个概念,这几个概念通了原型链也就差不多了.
- 1 构造函数/Class: 在js中我们创建一个引用数据类型的时候,可以通过其构造函数或者Class创建.这样创建出来的叫做它的实例.
- 2 对象原型:所有引用类型都会有一个对象原型(proto)他是一个普通的对象.也叫隐式原型.
- 3 原型对象:所有的函数都会有一个原型对象(prototype)他也是一个普通的对象,也叫显示原型
- 4 构造器: 构造函数的原型对象上会有一个constructor属性,该属性指回该构造函数.
function Fn() {
this.name = '实例';
}
const fn = new Fn();
console.log(Fn); //ƒ Fn() {this.name = '实例';} -构造函数
console.log(fn); // Fn {name: '实例'} -实例
console.log(fn.__proto__); // {constructor: ƒ} -对象原型
console.log(Fn.prototype); // {constructor: ƒ} -原型对象
console.log(Fn.prototype.constructor); //ƒ Fn() {this.name = '实例';} -构造器
原型链
既然每个对象他都有自己的对象原型,对象原型也是一个对象,那么对象原型也有自己的对象原型,就可以一直延伸,形成一个链状的关系.
function Fn() {
this.name = '实例';
}
const fn = new Fn();
console.log(fn.__proto__); //{constructor: ƒ}
console.log(fn.__proto__.__proto__); //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
console.log(fn.__proto__.__proto__.__proto__); //null
console.log(fn.__proto__.__proto__.__proto__.__proto__); //Uncaught TypeError: Cannot read properties of null (reading '__proto__')
我们可以看这个打印结果,发现确实可以一直查找.但是最后2个结果比较意外了,那就是null和报错.因为null并不是引用数据类型,所以他们对象原型.还可以得出一个结论那就是null就是原型链的尽头.
原型链的作用
我们知道了原型链的形成了,那么他有什么作用呢.看一段代码
function Fn() {
this.name = '实例';
}
Fn.prototype.eat = () => '吃饭';
Fn.prototype.name= '实力';
const fn = new Fn();
console.log(fn.name); // 实例
console.log(fn.eat()); // 吃饭
console.log(fn.toString()); // [object Object]
我们的构造函数Fn里面只有一个属性就是name.在下面的打印中 我们打印了属性name,方法eat,方法toString.那么方法eat和toString是哪里来的呢? 可以看到有一句这个代码Fn.prototype.eat = () => '吃饭'; 我们在Fn的对象原型上添加了eat方法,而toString,是Object的对象原型上的方法. 所有我们得知,当我们调用一个对象上的方法或者属性的时候,他会去使用原型链上的方法. 还有一个问题,我们在Fn的原型链式也有一个name属性,他为什么没有被调用呢,原因就是我们查找原型链之前会先查找自身是否有该属性或者改方法.