JS 原型与继承
参考来源:继承与原型链 - JavaScript | MDN (mozilla.org)
本文为个人学习记录,仅供参考
原型与原型链
在 JS 中,每个对象都有一个私有属性指向另一个名为原型 prototype的对象。原型对象也有一个自己的原型,层层向上直到一个对象的原型为 null。根据定义,null 没有原型,并作为这个原型链 prototype chain中的最后一个环节
PS: 对象的原型可以通过 __proto__ 属性访问,这个属性并非 ECMAScript 标准,不过众多 JS 引擎都实现了该属性
按照 ECMAScript 规范,应该使用
Object.getPrototyoeof()和Object.setPrototypeof()来访问对象原型
当访问对象上的属性时,JS 首先会检查它们是否直接存在于该对象上,如果不存在,则会顺着原型链查找,直至找到或者返回 undefined
函数的 prototype 属性
在 JS 中,每个函数都有一个属性 prototype,但其并非函数本身的原型
该属性值是一个对象,该对象中的 constructor 默认为函数本身
对于普通函数来说,该属性基本无用,但对于构造函数来说,构造实例的时候,便会将其分配给实例对象的原型
function A {}
A.prototype === A.__proto__ // false
A.prototype // { constructor: A }
const a = new A()
a.__proto__ === A.prototype // true
函数的构造函数为 Function,所以其原型指向 Function.prototype,其值是由 JS 引擎的提供,JS 无法解析
A.__proto__ === Function.prototype // true
Function.prototype // f () { [native code] }
JS 中的内置构造函数的原型和prototype 属性会有些特殊。但原型链的最后都指向 Object.prototype,而 Object.prototype 的原型指向 null
Object.__proto__ // f () { [native code] }
Function.__proto__ // f () { [native code] }
String.prototype == '' // true
String.prototype === '' // false
Array.prototype.map((x) => x) // []
Number.prototype == 0 // true
// ...
Function.prototype.__protot__ === Object.prototype // true
Object.__proto__.__proto__ === Object.prototype // true
Object.prototype.__proto === null // true
类与继承
JS 中没有传统意义上的类,ES6 的 class 本质是构造函数的语法糖
class A {}
A instanceof Function // true
创建对象实例
JS 中通过 new 操作符和构造函数来创建对象实例,大致步骤如下:
- 创建一个空对象
- 将这个空对象的原型,指向构造函数的
prototype属性 - 将函数内部的
this指向这个对象 - 执行构造函数内部的代码
- 如果构造函数没有返回对象,则返回
this
基于原型链的继承
根据原型的特点,我们可以根据实际情况编写合适的代码来定制继承方式
下面是最常见的一种继承方式,被称之为寄生组合继承
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
// 1.调用父类构造函数,继承父类的属性
Parent.call(this, value)
}
// 2.以父类 prototype 作为子类的 prototype
Child.prototype = Object.create(Parent.prototype)
// 3.将子类 prototype 中的 constructor 指向子类本身
Child.prototype.constructor = Child
const child = new Child(1)
child instanceof Child // true
child instanceof Parent // true
child.getValue() // 1
ES6 class 继承
使用 class 就非常方便了
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
// 1.使用 extends 关键字表示继承
class Child extends Parent {
constructor(value) {
// 2.在构造函数中调用 super 方法,类似 Parent.call(this, value)
super(value)
this.val = value
}
}
const child = new Child(1)
child instanceof Child // true
child instanceof Parent // true
child.getValue() // 1