javascript 如何创建一个可以调用任何方法的JS对象?

xtfmy6hx  于 2023-01-11  发布在  Java
关注(0)|答案(4)|浏览(137)

我想创建一个javascript对象,我可以调用任何方法,而不必定义它们,理想情况下,我可以调用它,就好像它是一个函数一样,它会调用一个我定义的函数,并将调用的函数名作为它的参数。
所以我会用callMethod(methodName)方法定义一个对象,当我调用

thisObject.doAThing();

它将称为thisObject.callMethod("doAThing");
这在javascript中是可能的吗?

vlju58qv

vlju58qv1#

不,这是不可能的。如果一个JavaScript对象没有属性,那么你就不能把未定义的值当作一个方法。

bcs8qyzn

bcs8qyzn2#

至少在Firefox中,您可以使用神奇的方法__noSuchMethod__来实现您的目标:

var o = {}
o.__noSuchMethod__ = function(id, args) { alert(id + args); }
o.foo(2,3) //will alert "foo" and "2,3"

请注意,这不是标准配置,正在考虑删除,因此不会添加到V8中。

eoigrqb6

eoigrqb63#

原帖(抱歉,应该在q评论中问这个问题):
如果callMethod可以访问某个地方的'doAThing'方法,为什么不能在对象示例化时或callMethod的源代码添加了新方法时插入该方法呢?
不是想纠缠你,只是想看看,在调用/应用/原型范式的疯狂世界里,是否有可能容纳你希望用其他方法实现的东西。
在此注解后添加的编辑:
我想创建一个代理对象,将其调用委托给另一个对象。- msfeldstein
好吧,prototype可能是答案,因为它基本上是作为对象本身没有的方法的后备。每个函数都有一个prototype属性,基本上只是一个普通的对象。当函数被用作构造函数时,当您调用构造函数示例上不具有的属性时,分配给构造函数原型的方法和属性将成为构造函数示例的后备。你可以向原型对象添加属性,它们将有效地为已经创建的示例所用,所以我在关联对象的情况下考虑了类似的事情:

//A js constructor is just a function you intend to invoke with the 'new' keyword
//use of 'this.property' will make that property public in the instance
//var effectively makes it private
//Constructors funcs differ from classes in that they don't auto-handle inheritance down to other constructors. You have to come up with a prototype merging scheme to do that.

function MyFacadeConstructor(){ //expected args are objects to associate
        var i = arguments.length; //arguments is a collection of args all funcs have
        while(i--){
            var thisObj = arguments[i];
            associateObjMethods(thisObj);
        }

        //makes it public method but allows function hoisting internally
        this.associateObjMethods = associateObjMethods;
        function associateObjMethods(obj){
            for(var x in obj){
                if(obj[x].constructor.name === 'Function'){ //normalize for <= IE8
                    MyFacadeConstructor.prototype[x] = obj[x];
                    //or if we literally want the other method firing in its original context
                    //MyFacadeConstructor.prototype[x] = function(arg){ obj[x](arg); }
                    //Not sure how you would pass same number of arguments dynamically
                    //But I believe it's possible
                    //A workaround would be to always pass/assume one arg
                    //and use object literals when multiple are needed
                }
            }
        }
    }

    function FirstNameAnnouncer(){
      this.alertFirst = function(){
          alert('Erik');
      }
    }

    var fNamer = new FirstNameAnnouncer();

    var newFacade = new MyFacadeConstructor(fNamer);

    //newFacade.alertFirst should work now;
    newFacade.alertFirst();

    //but we can also associate after the fact

    function LastNameAnnouncer(){
        this.alertLast = function(){ alert('Reppen'); }
    }

    var lNamer = new LastNameAnnouncer();

    newFacade.associateObjMethods(lNamer);

    //now newFacade.alertLast should work
    newFacade.alertLast();

现在,如果你想让调用对象的上下文变得重要,我推荐一个事件驱动的接口,这是JS非常适合的。如果你正在寻找的门面方法有什么方面我还没有在这里实现,请告诉我。

oalqel3c

oalqel3c4#

可以使用Proxy对象拦截任何方法调用。

function proxifyMethodCalls(obj) {
    const handler = {
        get(target, prop, receiver) {
            return function (...args) {
                console.log(`Intercepted '${prop}' with arguments ${JSON.stringify(args)}`);
                target.callMethod(prop);
            };
        }
    };
    return new Proxy(obj, handler);
}

let obj = {
    callMethod: (methodName) => {
        console.log(`'callMethod' called with '${methodName}'`);
    }
};
obj = proxifyMethodCalls(obj);

obj.doAThing(true);

相关问题