ES6类中的访问者组成

时间:2016-01-28 14:51:01

标签: javascript class ecmascript-6 mixins composition

假设我有一个Thing课程,我想同时成为HideableOpenable

使用类似的方法通过合成创建Douglas Crockford's对象,我已经能够从多个类“继承”。

此方法不适用于访问者(getter / setter)。

我需要使用类,因为它是一个要求。我也发现我在类之间复制功能,但我不希望它们从基类继承。

有什么想法吗?

到目前为止我所取得的进展如下:

class Openable {

  constructor(isOpen = false) {
    this._isOpen = isOpen;
  }

  get isOpen() {
    return this._isOpen + ' is stupid.';
  }

  set isOpen(value) {
    this._isOpen = value;
  }

}


class Hideable {

  constructor(isHidden = false) {
    this._isHidden = isHidden;
  }

  get isHidden() {
    return this._isHidden + ' is stupid.';
  }

  set isHidden(value) {
    this._isHidden = value;
  }

}


class Thing {

  constructor(config) {
    let { isOpen, isHidden } = config;

    let openable = new Openable(isOpen);
    this.isOpen = openable.isOpen;

    let hideable = new Hideable(isHidden);
    this.isHidden = openable.isHidden;
  }

}


let thing = new Thing({
  isOpen: true,
  isHidden: false
});

2 个答案:

答案 0 :(得分:6)

由于isOpenisHidden访问者,您不能只抓取它们的副本,您必须在需要时访问它们。

尽管如此,您仍然可以创建拥有的 isOpenisHidden使用底层的

let openable = new Openable(isOpen);
Object.defineProperty(this, "isOpen", {
    get: () => openable.isOpen,
    set: value => {
        openable.isOpen = value;
    }
});

let hideable = new Hideable(isHidden);
Object.defineProperty(this, "isHidden", {
    get: () => hideable.isHidden,
    set: value => {
        hideable.isHidden = value;
    }
});

Live example on Babel's REPL

当然,如果你做了很多,你想要一个工人功能来设置它而不是一直重新输入它:

function wrapProperty(dest, src, name) {
    Object.defineProperty(dest, name, {
        get: () => src[name],
        set: value => { src[name] = value; }
    });
}

(或通过抓取属性描述符并更新它来实现)

然后:

wrapProperty(this, openable, "isOpen");
wrapProperty(this, hideable, "isHidden");

我要求必须使用class OpenableHideable的要求。他们看起来更像是我的混合物。

答案 1 :(得分:0)

除了OP的访问者通过"伪私有财产" Openable / Hideable类的符号和原型getter / setter已经存在疑问,trait s最接近于使用类mixin代理的同样可疑的要求为了满足文件要求。

只要JavaScript本身不提供特征,就必须坚持使用more advanced class based mixin patterns一个人记住Angus Croll's Flight Mixins

一个必须写的mixin function主体足够接近constructor的{​​{1}}主体。然而,基于函数的mixin永远不会被实例化,但必须始终通过classcall应用于对象/类型。

一种可能的解决方案,采用这种mixin方法,已经可靠地满足OP的要求,可能看起来像下一个提供的示例代码......



apply

let
  Openable = (function openableMixinFactory () {
    let
      defineProperty = Object.defineProperty,
      isBoolean = (type => (typeof type == 'boolean'));

    return function openableMixinApplicator (isOpen = false) {
      let
        openableCompositeType = this,

        getIsOpen = (() => isOpen),
        setIsOpen = (value => ((isBoolean(value) && (isOpen = value)) || (void 0)));

      defineProperty(openableCompositeType, 'isOpen', {
        get: getIsOpen,
        set: setIsOpen,
        enumerable: true
      });
      return openableCompositeType;
    };
  }()),

  Hideable = (function hideableMixinFactory () {
    let
      defineProperty = Object.defineProperty,
      isBoolean = (type => (typeof type == 'boolean'));

    return function hideableMixinApplicator (isHidden = false) {
      let
        hideableCompositeType = this,

      //getIsHidden = (() => isHidden),
        getIsHidden = (() => [isHidden, 'is stupid.'].join(' ')),
        setIsHidden = (value => ((isBoolean(value) && (isHidden = value)) || (void 0)));

      defineProperty(hideableCompositeType, 'isHidden', {
        get: getIsHidden,
        set: setIsHidden,
        enumerable: true
      });
      return hideableCompositeType
    };
  }());


class Thing {
  constructor(config) {
    let
      {isOpen, isHidden} = config;

    Openable.call(this, isOpen);
    Hideable.call(this, isHidden);
  }
}


var
  thing = new Thing({ isOpen: true/*, isHidden: false*/ });

console.log('thing : ', thing);
console.log('thing.isOpen : ', thing.isOpen);
console.log('thing.isHidden : ', thing.isHidden);
console.log('(thing.isOpen = "xyz") : ', (thing.isOpen = "abc"));
console.log('(thing.isHidden = "xyz") : ', (thing.isHidden = "xyz"));
console.log('thing.isOpen : ', thing.isOpen);
console.log('thing.isHidden : ', thing.isHidden);
console.log('(thing.isOpen = false) : ', (thing.isOpen = false));
console.log('(thing.isHidden = true) : ', (thing.isHidden = true));
console.log('thing.isOpen : ', thing.isOpen);
console.log('thing.isHidden : ', thing.isHidden);




我在SO的其他答案,提供相似问题的类似解决方案,具有相同的方法是......