我有点困境。我正在使用ES6类来构建简单的类层次结构。一个带有方法的基类,3个子类覆盖该方法。在某个时候,我正在浏览我称之为此方法的实例列表。从技术上讲,如果我可以简单地保证我所有的对象(任何类型的对象(提供一个名称的方法,那么我不需要类层次结构。哪种方法更好?
class Base {
constructor() {
}
method() {
console.log('base')
}
}
class Subclass1 extends Base{
constructor() {
super()
}
method() {
console.log('sc1')
}
}
class Subclass2 extends Base{
constructor() {
super()
}
method() {
console.log('sc2')
}
}
class Subclass3 extends Base {
constructor() {
super()
}
method() {
console.log('sc3')
}
}
classInstances = [new Subclass1(), new Subclass2(), new Subclass3()];
classInstances.forEach(instance => {
instance.method();
})
// or using any kind of objects...
obj1 = {
method() {
console.log('obj1');
}
}
obj2 = {
method() {
console.log('obj2');
}
}
obj3 = {
method() {
console.log('obj3');
}
}
objectInstances = [obj1, obj2, obj3];
objectInstances.forEach(instance => {
instance.method();
})
是的,只需编程到接口。
您在任何地方都没有使用Base.prototype.method
,这是毫无意义的 - 因此将其丢弃。然后Base
只是一个空的类,几乎等同于Object
,因此也毫无意义。您实际上在这里没有使用任何继承功能,您也不需要类层次结构。
x instanceof Base
的测试是唯一剩下的用例,但是再次typeof x.method == "function"
更容易,更灵活。
javaScript使用'原型继承',而不是其他面向对象的语言的经典继承。这是一种合理的方法来测试一个对象是否基于给定的原型,但是鉴于可以自由地"修补" JavaScript对象以覆盖原型,甚至突变原型,因此您需要谨慎对待对象的假设。
如果您期望给定的方法存在,那么它可能更可靠地针对该方法进行测试,但是有时在代码中读取不太好。
您会遇到的一个问题是创建定义类型但没有默认行为的"基础"类。例如,在这里,我们可以为Animal
或Speakable
创建基本类型,但是speak
方法将需要是一个no-op或丢弃错误的方法。当然,当您无法定义预期行为时,这在开发过程中可能很有用。
另外,JavaScript不允许多个继承,因此您不能像其他语言那样实现"接口",尽管您可以创建获得类似结果的复合原型。
class Thing {
constructor(name) {
this.name = name
}
}
class Dog extends Thing {
speak() {
return 'woof';
}
}
class Cat extends Thing {
speak() {
return 'meow';
}
}
class House extends Thing {
}
const things = [new Dog('Rover'), new Cat('Tibbles'), new House('Foo Hall')];
things.forEach(thing => {
if (typeof thing.speak === 'function') {
console.log(`${thing.name} says '${thing.speak()}'`);
} else {
console.log(`${thing.name} cannot speak`);
}
});