如何在JavaScript中为多个类定义函数(而不是继承)?

7tofc5zh  于 2023-05-12  发布在  Java
关注(0)|答案(3)|浏览(283)

我需要定义一个可以被多个类使用的函数,但据我所知,从超类继承对我来说不起作用。本质上,我想要实现的是为每个类扩展多个接口的能力。
例如,如果我定义了AppleOrangeBanana类,我希望它们都有一个相同的isFresh()函数。我还喜欢让AppleOrangeEarth拥有一个getRadius()方法。这有点类似于Apple interface Fruit, SphericalObject {...}我也希望能够覆盖的功能,如果我想。然而,继承对我不起作用,因为我想从多个超类继承。
实现这一目标的最佳途径是什么?
我知道这个similar post,我理解JavaScript是动态类型的,没有接口,建议的Duck Type似乎不能解决我的问题。我并不关心检查接口中的方法是否存在于子类中。

a0zr77ik

a0zr77ik1#

看起来你在找“混合”它们不是内置在JavaScript中的,但在用户环境中很容易实现,例如:

function augment(cls, ...mixins) {
    return class extends cls {
        constructor(...args) {
            super(...args)

            for (let c of mixins)
                for (let p of Object.getOwnPropertyNames(c.prototype))
                    if (p !== 'constructor')
                        this[p] = c.prototype[p]
        }
    }
}

//

class Apple {}

class PhysicalObject {
    isFresh() {
        return 'hey'
    }
}

let AppleWithObject = augment(Apple, PhysicalObject)
let x = new AppleWithObject()
console.log(x.isFresh())
iklwldmw

iklwldmw2#

您只需要一个extends就可以实现您的结果。

class PhysicalObject {
   constructor(x,y) {this.x=x;this.y=y;}
   getPosition() {return {x:this.x,y:this.y}}
   displayPosition() {console.log(this.getPosition().x+', '+this.getPosition().y)}
   }
   
Earth=new PhysicalObject(0,0);
Earth.displayPosition();

class Fruit extends PhysicalObject {
  constructor(x,y,a) {super(x,y);this.age=a;}
  isFresh() {return this.age<7}
  }
  
Apple=new Fruit(1,1,6);
Apple.displayPosition();
console.log(Apple.isFresh());
yqyhoc1h

yqyhoc1h3#

关于被广泛误解的风险:受Douglas Crockford的启发,我停止使用类或原型(好吧,我在ES中从未使用过的类,never had any use for it)。
创建factory functions。这是一个示范性的水果工厂。
为了实现这个想法,我创建了一个小的Stackblitz project,使用了一种更通用的方法。

const FruitStore = FruitFactory();

FruitStore.apple = { 
  mustPeal: false, color: `red`, fresh: "Nope", origin: `Guatamala`, 
  inheritsFrom: {
    ...PhysicalObjectFactory(true), 
    ...ChemicalObjectFactory(true, null, true) },
};
FruitStore.orange = { inheritsFrom: {
  origin: `Spain`, fresh: false, color: `orange` } 
};
FruitStore.pineapple = { color: `yellow`, spherical: false, qty: `200Kg` };
console.log(FruitStore.all);
FruitStore.orange.fresh = `UNKNOWN`;
console.log(FruitStore.orange);

function PhysicalObjectFactory(spherical) {
  return { isPhysical: true, isSpherical: spherical };
}

function ChemicalObjectFactory(
  carbonBased = null, boilingPoint = null, solid = null) {
  return { carbonBased, boilingPoint, solid };
}

function FruitFactory() {
  let allFruits = {};
  // all fruits 'inherit' these properties
  // you can override any of them on
  // creating a fruit instance
  const fruitDefaults = {
    mustPeel: true,
    fresh: true,
    qty: `unset`,
  };
  const instance = { get all() { return allFruits; }, };
  // the proxy ensures you're working on the `allFruits` instance
  const proxy = { 
    get (obj, key) { return allFruits[key] ?? obj[key]; },
    set(_, key, props) { 
      allFruits[key] = createFruitInstance(key, props); 
      return true; 
    },
  };
  
  return new Proxy(instance, proxy);
  
  function createFruitInstance(name, props = {}) {
    const fruit = { name };
    let inherits = {};
    let inheritsFrom = { ...props.inheritsFrom };
    delete props.inheritsFrom;
    Object.entries({...fruitDefaults, ...props, ...inheritsFrom})
    .forEach( ([key, value]) => 
      value || key in fruitDefaults ? fruit[key] = value : false 
    );
    return fruit;
  }
}
.as-console-wrapper {
    max-height: 100% !important;
}

相关问题