我正在编码一个可链接库,并且我希望API允许将链的一部分作为静态值(具有默认值)以及有时作为函数来调用,以便可以将参数传递给它们。
var obj = {};
var chainCache = [];
Reflect.defineProperty(obj, 'color', {
get(){
chainCache.push('red');
return obj;
}
})
Reflect.defineProperty(obj, 'background', {
get(){
chainCache.push('black');
return obj;
}
})
Reflect.defineProperty(obj, 'end', {
value(){
var value = chainCache.join(" ");
chainCache.length = 0;
return value;
}
})
console.log( obj.color.background.end() ) // red black
这是一个非常简化的示例,实际上,我还想在上面的“ API”中包括一个功能,可以选择使用相同 color
键,如下所示:>
obj.color.background.end() // current API (great)
obj.color('#FF0').background.end() // optionally call "color" as function
obj.color().background.end() // bad API, I do not want this
color
可以同时称为功能和属性,具体取决于调用方式吗?
答案 0 :(得分:0)
我比预期的要认真地看待这个问题。随着Proxies的出现,这似乎是可能的。以您的示例为基础:
let chainCache = [];
let obj = {
color: new Proxy(()=>{}, {
get: (target, prop) => {
chainCache.push("red");
if(prop === "background") {
chainCache.push("black");
return { end: obj.end };
}
},
apply: (target, prop, args) => {
if(args.length > 0) {
chainCache.push(args.pop());
} else {
throw new Error("color expects argument if called like function");
}
return { background: new Proxy(()=>{}, {
get: (target,prop) => { chainCache.push("black"); return obj.end;}
})};
}
}),
end: () => {
let value = chainCache.join(" ");
chainCache = [];
return value;
}
};
console.log(obj.color.background.end());
console.log(obj.color("#FF0").background.end());
console.log(obj.color().background.end());
在调试控制台中,您将得到:
red black
#FF0 black
Error: color expects argument if called like function
从本质上讲,color是包装匿名箭头函数的代理,如果将color作为属性访问,则调用get()
陷阱;如果将color作为函数访问,则调用apply()
陷阱。这样就可以像您正在寻找的那样进行某种程度的元编程。
答案 1 :(得分:0)
您需要使obj
为函数。
一个函数仅仅是一个对象,并且可以具有属性-obj.color
必须返回一个具有属性(对于obj.color()
的函数(对于obj.color.background
)。
但是不,当访问getter时,您还不知道它是否将用于方法调用-obj.color()
是属性访问 plus 函数调用。
var chainCache = [];
var obj = Object.defineProperties(function obj(...args) {
chainCache.push(args);
return obj;
}, {
color: {
get() {
chainCache.push('color');
return obj;
}
},
background: {
get() {
chainCache.push('background');
return obj;
}
},
end: {
value: function() {
var res = chainCache.reduce((acc, val) =>
Array.isArray(val)
? `${acc}(${val.join(',')})`
: `${acc}.${val}`
, "obj");
chainCache.length = 0;
return res;
}
}
})