相当于 PHP 的 JavaScript __call
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10226064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript Equivalent Of PHP __call
提问by Fenton
In PHP you can detect when a method is called even when it doesn't exist using the "magic" __call
function.
在 PHP 中,您可以使用“魔术”__call
函数检测何时调用方法,即使该方法不存在。
public function __call($methodName, $args)
{
// do something
}
You can call any method and the name and arguments are passed to this magic catch-all.
您可以调用任何方法,并将名称和参数传递给这个神奇的包罗万象。
Is there a similar technique in JavaScript that would allow any method to be called even if it actually didn't exist on the object?
JavaScript 中是否有类似的技术允许调用任何方法,即使它实际上不存在于对象上?
var foo = (function () {
return {
__call: function (name, args) { // NOT REAL CODE
alert(name); // "nonExistent"
}
}
}());
foo.nonExistent();
采纳答案by amirnissim
It ispossible using the ES6 Proxy API:
它是使用ES6可能代理API:
var myObj = {};
var myProxy = new Proxy(myObj, {
get: function get(target, name) {
return function wrapper() {
var args = Array.prototype.slice.call(arguments);
console.log(args[0]);
return "returns: " + args[0];
}
}
});
console.log(myProxy.foo('bar'));
Browser compatibility is available on MDN. As of August 2017 all browsers (including Microsoft Edge) except Internet Explorer support it.
MDN上提供了浏览器兼容性。截至 2017 年 8 月,除 Internet Explorer 外的所有浏览器(包括 Microsoft Edge)都支持它。
See this answerfor a more complete look at Proxy.
请参阅此答案以更完整地了解代理。
回答by Romain Meresse
Obsolete since Gecko 43 (Firefox 43 / Thunderbird 43 / SeaMonkey 2.40)
自 Gecko 43 (Firefox 43 / Thunderbird 43 / SeaMonkey 2.40) 起已过时
You can use __noSuchMethod__
in Firefox. Unfortunately it is non standard...
您可以__noSuchMethod__
在 Firefox 中使用。不幸的是,它是非标准的...
Related question : Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?
回答by D. Ataro
To build upon @amirnissim's answer a slight bit.
稍微建立在@amirnissim 的回答之上。
As most of us are probably already aware, ES6 introduces the Proxy API, which allows us to create an object (the Proxy object) that traps calls to that object, whereby we are given an opportunity to "route" the attribute the user called on the object to whatsoever we may wish.
正如我们大多数人可能已经知道的那样,ES6 引入了 Proxy API,它允许我们创建一个对象(代理对象)来捕获对该对象的调用,从而我们有机会“路由”用户调用的属性任何我们希望的对象。
Mimicking PHP's Magic Methods
模仿 PHP 的魔法方法
There is unfortuantely no way to extend a class using the Proxy object, but what we can do is set up an intermediary step to turn an object into a proxy, and route any incoming method calls to the method available on the object itself:
不幸的是,没有办法使用 Proxy 对象扩展类,但我们可以做的是设置一个中间步骤,将对象转换为代理,并将任何传入的方法调用路由到对象本身可用的方法:
class MyProxy
{
constructor ()
{
return this.asProxy()
}
/**
* Return as a proxy with this object as its target.
*/
asProxy ()
{
let handler = {
/**
* This function is called whenever any property on the Proxy
* is called.
*
* @param target the "parent" object; the object the proxy
* virtualizes
* @param prop the property called on the Proxy
*/
get: function (target, prop)
{
/* This will return the property on the "parent" object
*/
if (typeof target[prop] !== 'undefined')
return target[prop]
// TODO: implement custom logic
}
}
return new Proxy(this, handler)
}
}
This essentially gives you the same functionality to PHP's magic __get
method and __call
method at the same time. As for the __call
version, we are simply returning a function for the user to enter arguments into.
这本质上同时为您提供了与 PHP 的魔法__get
方法和__call
方法相同的功能。至于__call
版本,我们只是返回一个函数供用户输入参数。
Demonstrating the Above
证明以上
In order to use this, let us first add a bit of custom logic to the place where the TODO: implement custom logic
resides:
为了使用这个,让我们首先在TODO: implement custom logic
驻留的地方添加一些自定义逻辑:
if (prop === 'helloWorld')
return function () { console.log("Hello, world!") }
else
return function () { console.log("Where art thou, hello world?") }
If we then go ahead and create a new instance of the MyProxy
class, we can trigger the custom logic we implemented:
如果我们继续创建类的新实例MyProxy
,我们可以触发我们实现的自定义逻辑:
let myProxy = new MyProxy()
myProxy.test()
myProxy.hello()
myProxy.helloWorld()
The above example outputs:
上面的例子输出:
Where art thou, hello world?
Where art thou, hello world?
Hello, world!
Where art thou, hello world?
Where art thou, hello world?
Hello, world!
It would, of course, also be possible to return any other type of value from the get
function, we could just as well return a string or an integer.
当然,也可以从get
函数返回任何其他类型的值,我们也可以返回字符串或整数。
Ease of Use; Usage Through Inheritance
便于使用; 通过继承使用
In order to make this even easier to use, may I suggest wrapping the asProxy
method into another class, then simply extending any class that needs the "magic method" functionality with the class containing the asProxy
method? By simply returning the asProxy
method from the constructor, you are basically given the same functionality you would see in PHP, in JavaScript.
为了使其更易于使用,我是否建议将该asProxy
方法包装到另一个类中,然后简单地使用包含该asProxy
方法的类扩展任何需要“魔术方法”功能的类?通过简单地asProxy
从构造函数返回该方法,您基本上可以获得与在 PHP 和 JavaScript 中看到的相同的功能。
Of course, it would also be somewhat required that the get method
is somewhat editable so that custom logic can still be handled from the subclass. Perhaps by sending in a closure to the return this.asProxy(() => {})
that is then called from the get
function itself? Or perhaps even route the get
function to a get
method present on the target
object?
当然,还有些需要get method
可编辑,以便仍然可以从子类处理自定义逻辑。也许通过向return this.asProxy(() => {})
然后从get
函数本身调用的闭包发送?或者甚至可能将get
函数路由到对象get
上存在的方法target
?
Do keep in mind, however, this is only ever applicable in ES6. Transpilers such as Babelcannot, and I quote:
但是请记住,这仅适用于 ES6。像 Babel 这样的转译器不能,我引用:
Due to the limitations of ES5, Proxies cannot be transpiled or polyfilled.
由于 ES5 的限制,代理不能被转译或填充。
The solution presented above does however work perfectly fine as long as this condition is met. It is, for instance, a perfectly viable option in Node.js.
然而,只要满足这个条件,上面提出的解决方案就可以很好地工作。例如,它是Node.js 中一个非常可行的选项。
回答by Chris Morgan
No. Due to the way JavaScript works, the equivalent would be like Python's __getattr__
/__getitem__
, rather than PHP's __call
, as it would need to be dealt with when retrieving the attribute rather than when calling it.
不。由于 JavaScript 的工作方式,等效项类似于 Python 的__getattr__
/ __getitem__
,而不是 PHP 的__call
,因为在检索属性时需要处理它,而不是在调用它时。
Then, you can look at a question like Python's __getattr__ in Javascriptwhich answers it in that way.
然后,您可以在 Javascript 中查看类似Python 的 __getattr__ 之类的问题,该问题以这种方式回答。
See also such questions as these:
另请参阅以下问题:
回答by Wildhoney
Although it's not an elegant way as we've already deduced that JavaScript does not have a __call
, method_missing
, __getattr__
it is possible to create combinations of properties to create concrete functions that relay to a single method, passing along the properties that were used to create it.
尽管这不是一种优雅的方式,因为我们已经推断出 JavaScript 没有__call
, method_missing
,__getattr__
但可以创建属性组合来创建传递给单个方法的具体函数,并传递用于创建它的属性。
One example is Myriad.js.
一个例子是Myriad.js。