我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

JavaScript语言里面,类的写法是有些畸形的。并不像其它高级编程语言一样,JavaScript里面的类,也可以写成函数的形式,也就是函数类。目前,还有个ES2015 class类,这个类和其它编程语言里面的类对比的话,比较相似了。本文说的是函数类的继承问题。

苏南大叔:JavaScript,函数类如何实现子类?函数类继承 - 函数类继承
JavaScript,函数类如何实现子类?函数类继承(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0chrome@132.0.6834.84。这个函数类的继承写法,挺不好用的,并不建议使用。目前已经不推荐使用函数类了,本文仅作了解。

类继承代码一 Man函数类

function Person(who) {
  this.who = who;
  this.earnCoin = function (coin) {
    console.info(this.who + " earn coin " + coin);
  };
}
function Man(who, city) {
  Person.call(this, who); // 调用父类构造函数,这里已经完成了继承
  this.city = city;
}
Man.prototype = Object.create(Person.prototype, { // 这里修复原型链
  constructor: {
    value: Man,
    enumerable: false,
    writable: true,
    configurable: true,
  },
});
const sunan = new Man("苏南", "北京");
console.log("sunan 是 Man 类的实例吗?", sunan instanceof Man); // true
console.log("sunan 是 Person 类的实例吗?", sunan instanceof Person); // true
sunan.earnCoin(1000); // 苏南 earn coin 1000  继承自父类的方法

输出:

sunan 是 Man 类的实例吗? true
sunan 是 Person 类的实例吗? true
苏南 earn coin 1000

苏南大叔:JavaScript,函数类如何实现子类?函数类继承 - 原型链修复
JavaScript,函数类如何实现子类?函数类继承(图3-2)

类继承代码二 Woman函数类

function Person(who) {
  this.who = who;
  this.earnCoin = function (coin) {
    console.info(this.who + " earn coin " + coin);
  };
}
function Woman(who, city) {
  Person.call(this, who); // 调用父类构造函数,完成继承
  this.city = city;
  this.earnCoin = function (coin) { // 覆盖父类方法
    console.info(this.who + "(" + this.city + ") cost coin " + coin);
  };
}
const xmm = new Woman("xmm", "朝阳");
console.log("xmm 是 Woman 类的实例吗?", xmm instanceof Woman); // true
console.log("xmm 是 Person 类的实例吗?", xmm instanceof Person); // false,由于没有修正prototype,所以这里是false
xmm.earnCoin(1000); // xmm(朝阳) cost coin 1000

输出:

xmm 是 Woman 类的实例吗? true
xmm 是 Person 类的实例吗? false
xmm(朝阳) cost coin 1000

苏南大叔:JavaScript,函数类如何实现子类?函数类继承 - 没有修复原型链的话,并不影响实质的继承
JavaScript,函数类如何实现子类?函数类继承(图3-3)

代码解说

【原型链链链链链链链链链...】父类是Person,子类有两个:ManWoman

  • 其中,Man通过Object.create()修改了prototype。其最直接的结果就是,在instanceof实例测试中,sunan通过了ManPerson两个类instanceof测试。
  • 而,Woman没有修改prototype。所以,在实例测试中,xmm没有通过Personinstanceof测试。

函数类继承

“继承”这个动作,来自于:

Person.call(this);

当然,也可以使用.apply()或者.bind()。参考文章:

原型链修复

而体现“继承”的原型链修复,代码来自于:

// 通过修改`prototype`的方式,修改了构造函数`constructor()`
Man.prototype = Object.create(Person.prototype, {
  constructor: {
    value: Man,
    enumerable: false,
    writable: true,
    configurable: true,
  },
});

这段代码,也可以换成:

Man.prototype = Object.create(Person.prototype);
Man.prototype.constructor = Man;
这两个“修复”方案,最终作用差不多。但是结果细节上还是有差异的,具体的可以打印.__proto__查看,这里不做描述。

Object.create(A,obj)的动作,是用来以参数A为原型,创造一个副本。然后通过obj参数,对这个副本进行修补处理。至于为啥要做这个修补,就不是苏南大叔所能描述清楚的了。

从上面的两个例子里面,可以看到:当不做这个修补的时候。子类的实例,就不会被判定为属于父类的实例。这和其它编程语言得出的常理,就有些偏差了。

结语

本文以叙述函数类的继承方式,以及存在的原型链上的一点小瑕疵为主要内容。更多苏南大叔的经验文章,请参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js