JavaScript,函数类如何实现子类?函数类继承
发布于 作者:苏南大叔 来源:程序如此灵动~ 我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...
在JavaScript
语言里面,类的写法是有些畸形的。并不像其它高级编程语言一样,JavaScript
里面的类,也可以写成函数的形式,也就是函数类。目前,还有个ES2015 class
类,这个类和其它编程语言里面的类对比的话,比较相似了。本文说的是函数类的继承问题。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,chrome@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
类继承代码二 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
代码解说
【原型链链链链链链链链链...】父类是Person
,子类有两个:Man
和Woman
。
- 其中,
Man
通过Object.create()
修改了prototype
。其最直接的结果就是,在instanceof
实例测试中,sunan
通过了Man
和Person
两个类instanceof
测试。 - 而,
Woman
没有修改prototype
。所以,在实例测试中,xmm
没有通过Person
类instanceof
测试。
函数类继承
“继承”这个动作,来自于:
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
参数,对这个副本进行修补处理。至于为啥要做这个修补,就不是苏南大叔所能描述清楚的了。
从上面的两个例子里面,可以看到:当不做这个修补的时候。子类的实例,就不会被判定为属于父类的实例。这和其它编程语言得出的常理,就有些偏差了。
结语
本文以叙述函数类的继承方式,以及存在的原型链上的一点小瑕疵为主要内容。更多苏南大叔的经验文章,请参考:
如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。