我需要可连接的' setters,允许你做以下事情:
cool_shoes = new Shoes().color('glitter').style('platform')
console.log(cool_shoes.color()) // => 'glitter'
但我已经厌倦了一遍又一遍地编写相同的getter和setter代码,以及:
function Shoes() { this._color = null; this._style = null; }
Shoes.prototype.constructor = Shoes;
Shoes.prototype.color = function(arg) {
if (arguments.length === 0) {
return this._color; // _slot accessor
} else {
this._color = arg; // _slot setter
return this;
};
};
Shoes.prototype.style = function(arg) {
if (arguments.length === 0) {
return this._style; // _slot accessor
} else {
this._style = arg; // _slot setter
return this;
};
};
我的意思是,这很有效,但是当你应该能够做类似的事情时,它会重复很多:
function createGetterSetter(getter, setter) {
return function(arg) {
if (arguments.length === 0) {
return getter();
} else {
setter(arg);
return this;
};
};
};
然后像这样使用它:
Shoes.prototype.color = createGetterSetter(
function() { return this._color; },
function(arg) { this._color = arg; });
Shoes.prototype.style = createGetterSetter(
function() { return this._style; },
function(arg) { this._style = arg; });
当然,正如任何勤奋的javascript向导所知道的那样,它不会起作用:this
或getter
在setter
或.bind(this)
时不会被绑定到正确的值被称为。
尽管我尽最大努力将createGetterSetter
洒在所有正确的地方,但我仍然无法将其付诸实践。这应该相对简单,但我缺少什么?
这里有一些富有想象力和优雅的答案,由于以前的默认原因,我仍然会使用Bryan Chen's answer:我的setter和getter需要做的不仅仅是引用对象属性。例如,在我的实际应用程序中,我调用了Command.prototype.messageType = utils.createGetterSetter(
function() { return messageType(this._payload).toString(); },
function(str) { messageType(this._payload).write(str); });
,如下所示:
foreach
...所以在我的案例中,简单地获取或设置对象中的插槽的解决方案不会起作用。但是,谢谢大家的一些好答案!
答案 0 :(得分:6)
如您所知,问题this
未在getter
和setter
上设置,那么为什么不设置它?
function createGetterSetter(getter, setter) {
return function(arg) {
if (arguments.length === 0) {
return getter.call(this); // pass this to getter
} else {
setter.call(this, arg); // pass this to setter
return this;
};
};
};
function Shoes() { this._color = null; this._style = null; }
Shoes.prototype.constructor = Shoes;
Shoes.prototype.color = createGetterSetter(
function() { return this._color; },
function(arg) { this._color = arg; });
Shoes.prototype.style = createGetterSetter(
function() { return this._style; },
function(arg) { this._style = arg; });
var cool_shoes = new Shoes().color('glitter').style('platform')
document.write(cool_shoes.color())

答案 1 :(得分:1)
接受的答案已经很好,但我会尝试更进一步。有时getter和setter分别需要的不仅仅是0和1个参数,所以我把更全面的东西放在一起:
game.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
statusbar.setText(String.format("Your mouse is at %d, %d", e.getX(), e.getY()));
}
public void mouseExited(MouseEvent e){
ifPaused = true;
}
public void mouseEntered(MouseEvent e){
ifPaused = false;
}
});

基本上我们将function Chain() {
this._methods = {};
}
Chain.prototype.overload = function(key, method) {
if (typeof key !== 'string') {
throw new TypeError('key must be a string.');
}
if (typeof method !== 'function') {
throw new TypeError('method must be a function.');
}
let attr, len = method.length;
if ((attr = (
this._methods.hasOwnProperty(key) && this._methods[key]
) || {}
) && attr[len]) {
throw new RangeError(`method ${key} of length ${len} already exists.`);
}
attr[len] = method;
if (!this._methods.hasOwnProperty(key)) {
this._methods[key] = attr;
this[key] = function (...args) {
let method = this._methods[key][args.length];
if (typeof method !== 'function') {
throw new ReferenceError(`method ${key} of length ${args.length} does not exist.`);
}
let value = method.apply(this, args);
return (typeof value === 'undefined' ? this : value);
}
}
};
function Shoes() { this._color = null; this._style = null;}
Shoes.prototype = new Chain();
Shoes.prototype.overload('color', function() { return this._color; });
Shoes.prototype.overload('color', function(arg) { this._color = arg; });
Shoes.prototype.overload('style', function() { return this._style; });
Shoes.prototype.overload('style', function(arg) { this._style = arg; });
Shoes.prototype.overload('value', function() {
return { color: this._color, style: this._style };
});
Shoes.prototype.overload('value', function(attr) { return this[attr](); });
Shoes.prototype.overload('value', function(attr, arg) { this[attr](arg); });
var cool_shoes = new Shoes().color('glitter').style('platform');
document.write(JSON.stringify(cool_shoes.value()));
构造为Chain()
,因此我们可以为Shoes.prototype
的实例重载成员方法。
Shoes()
函数采用overload()
和key
,确定方法签名中的参数数量,并将其添加到方法名称的可用签名中由method
给出。如果已存在具有指定函数中的参数数量的签名,则key
将引发错误。如果调用具有未声明签名的函数,它也会抛出错误。
否则,setter链正确(假设他们没有返回任何东西)和getters正确返回它们的值。
根据要求,这里有一个overload()
版本作为mixin而不是超类提供:
Chain()
function chain() {
let _methods = {};
return function overload(key, method) {
if (typeof key !== 'string') {
throw new TypeError('key must be a string.');
}
if (typeof method !== 'function') {
throw new TypeError('method must be a function.');
}
let attr, len = method.length;
if ((attr = (
_methods.hasOwnProperty(key) && _methods[key]
) || {}
) && attr[len]) {
throw new RangeError(`method ${key} of length ${len} already exists.`);
}
attr[len] = method;
if (!_methods.hasOwnProperty(key)) {
_methods[key] = attr;
this[key] = function (...args) {
let method = _methods[key][args.length];
if (typeof method !== 'function') {
throw new ReferenceError(`method ${key} of length ${args.length} does not exist.`);
}
let value = method.apply(this, args);
return (typeof value === 'undefined' ? this : value);
}
}
};
}
答案 2 :(得分:0)
这个怎么样?
function ToyClass() { this._c = 0; }
ToyClass.prototype.constructor = ToyClass;
function addFn( CLASS, ident, uncurriedMutation ) {
CLASS.prototype[ident] = function( ...args ) {
uncurriedMutation( this ).apply(this, args )
return this
}
}
addFn(ToyClass, 'increase', function( instance ){
return function(){
(instance._c)++
}
})
const testCase = new ToyClass().increase()
console.log(testCase._c) // will be '1'
编辑:Simplified version.谢谢@Patrick Roberts
答案 3 :(得分:0)
_
开头的属性设置它们,但为了简单起见,这将完成所有这些操作。
您只需要:
Object.keys(new Shoes()).forEach(field => {
let name = field.slice(1); // Remove underscore
Shoes.prototype[name] = function(val) {
if (val) {
this[field] = val;
return this;
}
return this[field];
};
});
它在Shoes
原型中创建了一个新函数,用作getter和setter。使用cool_shoes.color("red")
会将_color
属性设置为red
,只需调用不带参数的函数(cool_shoes.color() === "red"
)即可检索。
我正在考虑创建此功能而不使用新的Proxy
对象显式创建所有getter和setter,但无法弄清楚。也许你会有更多的运气!