一点javascript元编程&;链式设定器
我需要“可链接”设置器,允许您执行以下操作:一点javascript元编程&;链式设定器,javascript,metaprogramming,fluent,Javascript,Metaprogramming,Fluent,我需要“可链接”设置器,允许您执行以下操作: 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.prototyp
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; });
Command.prototype.messageType = utils.createGetterSetter(
function() { return messageType(this._payload).toString(); },
function(str) { messageType(this._payload).write(str); });
当然,任何努力工作的javascript向导都知道,它不会工作:this
在调用getter
或setter
时不会绑定到正确的值
尽管我尽了最大努力将.bind(this)
洒在所有正确的地方,但我仍然没有让它发挥作用。这应该相对简单,但我遗漏了什么
更新
这里有一些富有想象力和优雅的答案,出于一个先前默认的原因,我仍然坚持:我的setter和getter需要做的不仅仅是引用对象属性。例如,在我的实际应用程序中,我调用了createGetterSetter
,如下所示:
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; });
Command.prototype.messageType = utils.createGetterSetter(
function() { return messageType(this._payload).toString(); },
function(str) { messageType(this._payload).write(str); });
。。。因此,简单地在对象中获取或设置一个槽的解决方案在我的情况下不起作用。但谢谢你们所有人给了我一些很棒的答案 正如您所知,问题是
此
未设置在getter
和setter
上,因此为什么不设置它呢
函数createGetterSetter(getter,setter){
返回函数(arg){
if(arguments.length==0){
return getter.call(this);//将此传递给getter
}否则{
调用(this,arg);//将此传递给setter
归还这个;
};
};
};
函数({this.\u color=null;this.\u style=null;}
Shoes.prototype.constructor=鞋;
Shoes.prototype.color=createGetterSetter(
函数(){返回此值。_color;},
函数(arg){this.\u color=arg;});
Shoes.prototype.style=createGetterSetter(
函数(){返回此。_style;},
函数(arg){this.\u style=arg;});
var cool_shoes=新鞋().颜色('glitter').款式('platform'))
document.write(cool_shoes.color())
这个怎么样
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'
编辑:谢谢@Patrick Roberts公认的答案已经很好了,但我将尝试更进一步。有时getter和setter分别需要的参数不仅仅是0和1,所以我将一些更全面的内容放在一起:
功能链(){
这个。_方法={};
}
Chain.prototype.重载=函数(键、方法){
如果(键的类型!=='string'){
抛出新类型错误('键必须是字符串');
}
如果(方法类型!==‘函数’){
抛出新的TypeError('方法必须是函数');
}
设attr,len=method.length;
如果((属性=(
this._methods.hasOwnProperty(key)和&this._methods[key]
) || {}
)&&attr[len]){
抛出新的RangeError(`method${key}的长度${len}已经存在。`);
}
attr[len]=方法;
如果(!this._methods.hasOwnProperty(键)){
这._方法[key]=attr;
此[键]=函数(…参数){
让method=this._方法[key][args.length];
如果(方法类型!==‘函数’){
抛出新的ReferenceError(${args.length}长度的`method${key}不存在。`);
}
让value=method.apply(这是args);
返回值(typeof value===“未定义”?此:值);
}
}
};
函数({this.\u color=null;this.\u style=null;}
Shoes.prototype=新链条();
重载('color',function(){返回此值。_color;});
重载('color',function(arg){this.\u color=arg;});
重载('style',function(){returnthis.\u style;});
重载('style',function(arg){this.\u style=arg;});
Shoes.prototype.重载('value',function()){
返回{color:this.\u color,style:this.\u style};
});
重载('value',函数(attr){返回这个[attr]();});
重载('value',函数(attr,arg){this[attr](arg);});
var cool_shoes=新鞋().颜色('glitter').款式('platform');
document.write(JSON.stringify(cool_shoes.value())代码>我也迟到了,但我觉得这是一个有趣的问题。这里有一个解决方案,可以为对象中的所有属性动态创建可链接的getter和setter。您可以很容易地将其限制为仅为以开头的属性生成它们,但为简单起见,这会生成所有属性
您所需要的只是:
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\u shoes.color(“red”)
将\u color
属性设置为red
,只需调用不带参数的函数即可检索(cool\u shoes.color()==“red”
)
我正在考虑在没有使用新对象显式创建所有getter和setter的情况下创建这个功能,但是没有弄清楚。也许你会有更多的运气 干净简单——感谢您提供了一个很棒的通用方法(以及闪亮的鞋子)。您应该使用getter.call(this)
/setter.call(this,arg)
而不是在任何地方使用bind
。实际上,我希望createGetterSetters(shoes.prototype,[“color”,“style”]))
如果您的目的是避免重复:-)@Bergi在本例中,签名会起作用,但一般来说,getter和setter可能需要更多的功能,而不仅仅是分配或返回特定的field@PatrickRoberts:事实上,我发现这些非常罕见:-),如果您确实需要,您仍然可以为.
属性创建一个实际的setter/getter。@Bergi,考虑jQuery中处理同一个函数名的不同签名的函数。当您已经将这个
传递给实际的mutator时,为什么需要将实例
传递给外部作用域?e、 g.董事会