使对象或 class 属性 仅可调用
Make object or class property only invocable
TL:DR;是否可以使 属性 对象仅可调用(作为函数)?
我的意思
class Foo{
bar(value){
return value
}
}
let newFoo = new Foo()
console.log(newFoo.bar(123)) // should work fine as function is invoked
console.log(newFoo.bar) // here i need to throw or display an error instead of returning value
我试图用 Proxy
and handler.get
陷阱来做到这一点,但我不知道如何捕获它是一个函数调用还是只是 属性 访问,
class Foo {
bar(value) {
return value
}
}
const proxied = new Proxy(new Foo(), {
get: function(target, prop, reciver) {
if (prop === 'bar') {
throw new Error('Bar is method need to be invoced')
}
return target[prop]
}
})
console.log(proxied.bar(true))
console.log(proxied.bar)
我也检查了 handler.apply
但这似乎也没有用,因为这是一个功能陷阱,而不是 属性
class Foo {
bar(value) {
return value
}
}
const proxied = new Proxy(new Foo(), {
apply: function(target, thisArg, argumentsList) {
return target(argumentsList[0])
},
get: function(target, prop, reciver) {
if (prop === 'bar') {
throw new Error('Bar is method need to be invoced')
}
return target[prop]
}
})
console.log(proxied.bar(true))
console.log(proxied.bar)
不,这是不可能的。没有区别
const newFoo = new Foo()
newFoo.bar(123);
和
const newFoo = new Foo()
const bar = newFoo.bar;
Function.prototype.call.call(bar, newFoo, 123); // like `bar.call(newFoo, 123)`
// or Reflect.apply(bar, newFoo, [123]);
即newFoo
和bar
都无法区分这些"from the inside"。现在在 属性 访问和方法调用之间可能发生任意事情,并且在 属性 访问期间您无法知道接下来会发生什么,因此您不能过早地抛出异常。方法调用可能永远不会发生(在 newFoo.bar;
中),并且无法仅从 newFoo
中识别出这一点。
唯一的方法是拦截对 newFoo
及其属性的所有其他访问,并且 throw
在 您检测到恶意序列之后;可能让你的 "linter" 在整个程序 运行:
之后从外部检查序列
const lint = {
access: 0,
call: 0,
check() {
console.log(this.access == this.call
? "It's ok"
: this.access > this.call
? "method was not called"
: "property was reused");
},
run(fn) {
this.call = this.access = 0;
try {
fn();
} finally {
this.check();
}
}
}
function bar(value) {
lint.call++; lint.check();
return value;
}
class Foo {
get bar() {
lint.check(); lint.access++;
return bar;
}
}
lint.run(() => {
const newFoo = new Foo;
newFoo.bar(123);
});
lint.run(() => {
const newFoo = new Foo;
newFoo.bar;
});
lint.run(() => {
const newFoo = new Foo;
const bar = newFoo.bar;
bar(123);
bar(456);
});
更好的解决方案可能是为简单表达式编写您自己的解释器,它只允许方法调用。
TL:DR;是否可以使 属性 对象仅可调用(作为函数)?
我的意思
class Foo{
bar(value){
return value
}
}
let newFoo = new Foo()
console.log(newFoo.bar(123)) // should work fine as function is invoked
console.log(newFoo.bar) // here i need to throw or display an error instead of returning value
我试图用 Proxy
and handler.get
陷阱来做到这一点,但我不知道如何捕获它是一个函数调用还是只是 属性 访问,
class Foo {
bar(value) {
return value
}
}
const proxied = new Proxy(new Foo(), {
get: function(target, prop, reciver) {
if (prop === 'bar') {
throw new Error('Bar is method need to be invoced')
}
return target[prop]
}
})
console.log(proxied.bar(true))
console.log(proxied.bar)
我也检查了 handler.apply
但这似乎也没有用,因为这是一个功能陷阱,而不是 属性
class Foo {
bar(value) {
return value
}
}
const proxied = new Proxy(new Foo(), {
apply: function(target, thisArg, argumentsList) {
return target(argumentsList[0])
},
get: function(target, prop, reciver) {
if (prop === 'bar') {
throw new Error('Bar is method need to be invoced')
}
return target[prop]
}
})
console.log(proxied.bar(true))
console.log(proxied.bar)
不,这是不可能的。没有区别
const newFoo = new Foo()
newFoo.bar(123);
和
const newFoo = new Foo()
const bar = newFoo.bar;
Function.prototype.call.call(bar, newFoo, 123); // like `bar.call(newFoo, 123)`
// or Reflect.apply(bar, newFoo, [123]);
即newFoo
和bar
都无法区分这些"from the inside"。现在在 属性 访问和方法调用之间可能发生任意事情,并且在 属性 访问期间您无法知道接下来会发生什么,因此您不能过早地抛出异常。方法调用可能永远不会发生(在 newFoo.bar;
中),并且无法仅从 newFoo
中识别出这一点。
唯一的方法是拦截对 newFoo
及其属性的所有其他访问,并且 throw
在 您检测到恶意序列之后;可能让你的 "linter" 在整个程序 运行:
const lint = {
access: 0,
call: 0,
check() {
console.log(this.access == this.call
? "It's ok"
: this.access > this.call
? "method was not called"
: "property was reused");
},
run(fn) {
this.call = this.access = 0;
try {
fn();
} finally {
this.check();
}
}
}
function bar(value) {
lint.call++; lint.check();
return value;
}
class Foo {
get bar() {
lint.check(); lint.access++;
return bar;
}
}
lint.run(() => {
const newFoo = new Foo;
newFoo.bar(123);
});
lint.run(() => {
const newFoo = new Foo;
newFoo.bar;
});
lint.run(() => {
const newFoo = new Foo;
const bar = newFoo.bar;
bar(123);
bar(456);
});
更好的解决方案可能是为简单表达式编写您自己的解释器,它只允许方法调用。