JavaScript实现继承的三种核心方式详解
本文深入解析JavaScript中实现继承的三种主流方法。首先介绍利用Object.create构建类式继承的手动原型链设置;其次分析Node.js中util.inherits工具函数的实现原理及其对Object.setPrototypeOf的依赖;最后详解ES6 Class语法糖中extends关键字与super函数的使用规范,对比各方案在代码简洁性与执行效率上的差异。
基于Object.create的类式继承
利用Object.create方法可以实现类式继承模式。
参考官方文档提供的示例代码。
//Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
Rectangle.prototype = Object.create(Shape.prototype);
var rect = new Rectangle();
rect instanceof Rectangle //true.
rect instanceof Shape //true.
rect.move(1, 1); //Outputs, "Shape moved."
在此模式下,Rectangle原型的constructor属性默认指向父类构造函数。若需让实例识别自身构造函数,需手动修正该属性,具体做法如下。
Rectangle.prototype.constructor = Rectangle;
util.inherits工具函数解析
另一种方式是利用Node.js utilities工具包提供的util.inherits函数。
其标准语法格式如下。
util.inherits(constructor, superConstructor) 具体应用示例如下。
const util = require('util');
const EventEmitter = require('events');
function MyStream() {
EventEmitter.call(this);
}
util.inherits(MyStream, EventEmitter);
MyStream.prototype.write = function(data) {
this.emit('data', data);
}
var stream = new MyStream();
console.log(stream instanceof EventEmitter); // true
console.log(MyStream.super_ === EventEmitter); // true
stream.on('data', (data) => {
console.log(`Received data: "${data}"`);
})
stream.write('It works!'); // Received data: "It works!"
该实现过程相对直观,其底层源码实际上调用了ES6引入的新特性,我们进一步分析其内部机制。
exports.inherits = function(ctor, superCtor) {
if (ctor === undefined || ctor === null)
throw new TypeError('The constructor to "inherits" must not be ' +
'null or undefined');
if (superCtor === undefined || superCtor === null)
throw new TypeError('The super constructor to "inherits" must not ' +
'be null or undefined');
if (superCtor.prototype === undefined)
throw new TypeError('The super constructor to "inherits" must ' +
'have a prototype');
ctor.super_ = superCtor;
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
};
其中Object.setPrototypeOf即为ES6新特性,将一个指定的对象的原型设置为另一个对象或者null
其语法定义如下。
Object.setPrototypeOf(obj, prototype) 其中obj参数代表需要修改原型的对象。 prototype参数代表obj新的原型对象,该值可以是任意对象或null。
若将原型设置为null,则示例代码如下。
Object.setPrototypeOf({}, null); 从命名即可看出,该函数专注于处理prototype属性。那么其底层实现原理是什么?这需要借助非标准的__proto__属性来完成。
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
即直接将proto赋值给obj.__proto__即可完成原型链的构建。
ES6 Class与extends关键字
第三种方式是直接使用ES6的extends关键字。
熟悉Java语法的开发者对该关键字应不陌生,Java中的继承机制主要依赖此关键字。ES6新增的class关键字本质上是语法糖,其底层实现依然基于函数机制。
在以下示例中,首先定义了一个名为Polygon的类,随后定义了一个继承自Polygon的Square类。注意构造函数中使用了super()调用,super()仅能在构造函数内部使用,且必须在this关键字可用之前被调用。
class Polygon {
constructor(height, width) {
this.name = 'Polygon';
this.height = height;
this.width = width;
}
}
class Square extends Polygon {
constructor(length) {
super(length, length);
this.name = 'Square';
}
}
使用关键字后,无需再繁琐地手动设置原型链,该关键字已封装好相关逻辑,使用更加快捷方便。
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
