本文已参与「新人创作礼」活动,一起开启掘金创作之路。
关键词:
构造函数 原型对象 实例 prototype [[prototype]] __proto__
构造函数
function Student() {
this.name = 'Jane'
}
无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个 prototype 属性(指向原型对象)。默认情况下,所有的原型对象自动获取一个名为 constructor 的属性,并指向与之相关的构造函数。
Student // 创建函数
.prototype // 为函数创建一个 prototype 属性,指向原型
.constructor // 默认情况下,原型对象自动获得一个 constructor 属性,指向与之关联的构造函数
在自定义构造函数时,原型对象默认只会获得 constructor 属性,其他的所有方法和属性都继承自 Object。
实例
使用自定义构造函数创建一个实例后,这个实例的内部 [[Prototype]] 指针会被赋值为构造函数的原型对象。
const student = new Student();
[[Prototype]] 属性是不能直接访问的,也没有访问 [[Prototype]] 属性的标准。
访问内部特性 [[prototype]] 的方式:
1. __proto__ 属性
不过现代浏览器( Firefox、Safari 和 Chrome )会在对象上暴露 __proto__ 属性,我们可以通过该属性访问原型。
student.__proto__
//
student.__proto__ === Student.prototype // true
2. Object.getPrototypeOf() 方法
对于没有暴露 proto 属性的,可以使用 Object.getPrototypeOf() 方法获取内部特性 [[prototype]] 的值
Object.getPrototypeOf(student) === Student.prototype
构造函数和实例的关系
每个构造函数都有一个原型对象(prototype),原型有个属性(constructor)指回构造函数,实例内部有个指针(__proto__)指向原型。
构造函数、原型对象和实例是三个完全不同的对象
student !== Student
student !== Student.prototype
Student.prototype !== Student
- 实例可以通过 proto 属性链接到原型对象
- 构造函数可以通过 prototype 属性链接到原型对象
- 构造函数和实例没有关系,但是构造函数的原型和实例有直接的联系
student.__proto__ === Student.prototype // true
// or
Student.isPrototypeOf(student); // true
使用同一个构造函数构建出来的两个实例共享同一个原型对象:
const stu1 = new Student();
const stu2 = new Student();
stu2.__proto__ === stu1.__proto__
**instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。**
object instanceof constructor
// object 某个实例对象
// constructor 某个构造函数
console.log(student instanceof Student) // true
// 所有自定义对象都继承自 Object
console.log(student instanceof Object) // true
原型的特点
1. 动态性
实例在修改原型之前已经存在,任何时候对原型对象所做的修改会反映到实例上。因为从原型上搜索值的过程是动态的。 注意,重写构造函数上的原型之后创建的实例才会引用新的原型,而在之前创建的实例仍然会引用最初的原型。
2. 共享特性
原型上所有的属性是实例间都是共享的
原型的问题
- 弱化了向构造函数传递初始参数的能力,会导致所有实例默认都取得相同的属性。
- 最主要的问题是原型的共享特性。原型上所有的属性是实例间都是共享的,如果属性是原始值还好,如果属性是引用类型,就会有问题了。