JavaScript 的原型继承
JavaScript 继承
一般的面向对象的语言对继承的处理方式都是 class-based,即基于类的继承。一般是说子类继承了父类,继承的主体是类。而类的对象之间的继承体现于类的继承中。
以 Java 为例
1 | public class A{} // 父类 A |
在 JavaScript 的世界中则并非如此。JS 通过原型链的方式来实现继承,是基于对象的继承。下例中 b 对象继承了 a 对象的所有属性和方法。
1 | function People(sex) { |
在这里我们可以说,a 对象是 b 对象的原型。这样的继承方法不需要类,继承在对象之间完成。
原型继承机制
对象进行属性查找时,优先查找自己的属性,如果没有查找到再去查找对象的原型上的属性。如果原型对象依旧没有找到,那么递归查找指导原型根部,如果依旧没有找到那么返回 undefined。
1 | st=>start: 对象 a |
这就是原型链的思想,层层往上一级链条上查找。
ES5 中,可以通过 Object.getPrototypeOf (obj) 来获取 obj 对象的原型,在 Chrome 浏览器中也可以使用非标准的 obj.__proto__。
JS 中定义一个类的是通过声明一个函数来实现,这个函数也称为构造器。JS 中的构造器有一个特殊的属性 (函数也是对象,所以也有属性) ———— prototype。此 prototype 用来定义通过构造器构造出来的对象的原型,构造器内部的代码用来给对象初始化。如下
1 | function People(name) { |
我们可以看出 p1 对象获得了 People.prototype 的属性和方法。实际上,通过 new People (),p1 以 People 的 prototype 为原型来创建了一个新对象,并获得了该原型的全部属性和方法。
1 | p1 = new People() // 等价于 |
p1 的原型是 People.prototype,p1 是 People 构造 (new) 出来的。
为了让 p1.constructor 能构正确执行 p1 的构造器,一个构造器默认的 prototype 上已经存在 constructor 属性,并且指向构造器本身。
⚠️ People.prototype 并非 People 的原型,而是 People 构造的对象的原型,即 p1 的原型。People 本身是一个 Function 类型,你可以把它理解为一个 Function 构造出来的对象,它的原型是 Object.getPrototypeOf (People) 或 People.__proto__。 因为 People 是一个函数对象,所有函数都构造自 Function,原型是 Function.prototype。People.prototype 是 People 构造出来的实例的原型,不是 People 的原型。
1 | People.__proto__ === Function.prototype |
探究 constructor
1 | function Foo() {} |
在这个样例我们可以得知三个信息,
对于
foo对象而言,Foo函数是其构造器,foo是Foo函数构造的对象。对于一切函数
fn而言,Function是它们的构造器,fn是Function函数构造的对象,函数也是一种特殊的对象。Function的构造器是Function本身。Function既是对象,又是函数。
那么我们可以推断出什么?
因为所有的函数都有同一个构造器,所以所有的函数都有同一个原型,这个原型就是 Function 类的原型 Function.prototype
即 Object.getPrototypeOf (fn) === Function.prototype, 所有的函数都是一个类 。
Function 的双重性
1 | Function.__proto__ === Function.prototype //true |
等式的左边的 Function 作为对象,求 Function 对象继承的原型
等式的右边的 Funciton 作为构造器,求 Function 类的原型
而对于一般的函数来说则不能这么比较
1 | function Flower(){} |
所以 Function 是一种特殊的函数,也是一种特殊的对象。
- 它的构造器是它的自身。
- 它与所有的函数继承同一个原型。
- 所有的函数都由
Function来构造。
Object 与 Function
聊完 Function 再来聊聊 Object,JavaScript 原生提供 Object 对象。
1 | function Foo(){} |
可以看出,所有的对象都继承自 Object 对象。
Object 是所有 Object 对象的构造器,而根据 Function 的有趣性质,我们可以获得下面的结果
1 | Object instanceof Function //true |
首先,我们需要弄清楚 instanceof 的原理
1 | instance instanceof People // 等价于 |
JavaScript 中的继承概念归根到底是原型的继承,那么 instanceof 实际上就是将 instance 的原型与构造器的 prototype 进行递归检查。
Object 是一个构造器,一个函数,而函数也是一个对象,这个对象由 Function 这个构造器构造,所以
Object.__proto__ === Function.prototype 上式成立
Function 是一个函数,一个对象,而所有的对象都是继承于 Object 对象的原型,
Function.__proto__ === Object.prototype 下式成立
总结
- JavaScript 的继承是通过原型链继承来实现的
- 所有的函数都是对象,它们的构造器是
Function Function是自身的构造器- 所有的对象的最终原型是
Object.prototype,即所有的对象都继承于Object对象








