原型

今天说一下JS中原型和原型链,我理解的也不是很透彻,这边结合网上的一些文章,记录一下。

1. 原型 / 构造函数 / 实例

每个函数都有 prototype 属性,除了 Function.prototype.bind(),该属性指向原型。
每个对象都有proto属性,指向了创建该对象的构造函数的原型。其实这个属性指向了 [[prototype]],但是 [[prototype]] 是内部属性,我们并不能访问到,所以使用proto来访问。
对象可以通过proto来寻找不属于该对象的属性,proto将对象连接起来组成了原型链。
如果你想更进一步的了解原型,可以仔细阅读深度解析原型中的各个难点

  • 原型(prototype): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个proto (非标准)的属性指向它爹(该对象的原型),可obj__proto__进行访问。
  • 构造函数: 可以通过new来 新建一个对象 的函数。
  • 实例: 通过构造函数和new创建出来的对象,便是实例。
  • 实例通过proto指向原型,通过constructor指向构造函数。

可能有点懵逼,这里来举个栗子,以Object为例,我们常用的Object便是一个构造函数,因此我们可以通过它构建实例。

1
2
// 实例
const instance = new Object()

则此时, 实例为instance, 构造函数为Object,我们知道,构造函数拥有一个prototype的属性指向原型,因此原型为:

1
2
// 原型
const prototype = Object.prototype

这里我们可以来看出三者的关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
实例.__proto__ === 原型

原型.constructor === 构造函数

构造函数.prototype === 原型

// 这条线其实是是基于原型进行获取的,可以理解成一条基于原型的映射线
// 例如:
// const o = new Object()
// o.constructor === Object --> true
// o.__proto__ = null;
// o.constructor === Object --> false
实例.constructor === 构造函数

2.原型链:

原型链解决的主要是继承问题。
每个对象拥有一个原型对象,通过 proto (读音: dunder proto) 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null(Object.proptotype.proto指向的是 null)。这种关系被称为原型链 (prototype chain),通过原型链一个对象可以拥有定义在其他对象中的属性和方法。

  • 属性查找机制: 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象Object.prototype,如还是没找到,则输出undefined;
  • 属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2;但是这样会造成所有继承于该对象的实例的属性发生改变。

3.prototype 和 proto区别是什么?

prototype 是构造函数的属性。
proto是每个实例都有的属性,可以访问prototype属性。
实例的proto与其构造函数的 prototype 指向的是同一个对象。

1
2
3
4
5
6
7
8
9
10
11
function Student(name) {
this.name = name;
}
Student.prototype.setAge = function(){
this.age=25;
}
let Dabao = new Student('dabao');
console.log(Dabao.__proto__);
//console.log(Object.getPrototypeOf(Dabao));;
console.log(Student.prototype);
console.log(Dabao.__proto__ === Student.prototype);//true