假设我有一个Thing
课程,我想同时成为Hideable
和Openable
。
使用类似的方法通过合成创建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
});
答案 0 :(得分:6)
由于isOpen
和isHidden
是访问者,您不能只抓取它们的副本,您必须在需要时访问它们。
尽管如此,您仍然可以创建拥有的 isOpen
,isHidden
使用底层的
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;
}
});
当然,如果你做了很多,你想要一个工人功能来设置它而不是一直重新输入它:
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
Openable
和Hideable
的要求。他们看起来更像是我的混合物。
答案 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永远不会被实例化,但必须始终通过class
或call
应用于对象/类型。
一种可能的解决方案,采用这种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的其他答案,提供相似问题的类似解决方案,具有相同的方法是......