JavaScript相当于php __call

时间:2013-12-03 23:08:53

标签: javascript

我不认为有这样的事情,因为我想我现在已经找到了它,但唯一可以确定的方法就是给出一个直接的答案,因此我必须在放弃之前先问一下。我需要一个每次尝试访问对象方法时都会调用的方法。 JavaScript中有这样的东西吗?

基本上我需要在每个对象的方法之前和之后运行几行。对它们进行硬编码实际上不是一种选择。我想到的另一件事就是有一个像

这样的主要方法
Mainmethod(ActualMethod, Parameters)

但这对我来说真的不好看,我真的不想这样做。

3 个答案:

答案 0 :(得分:2)

如果这只是针对特定对象或特定类型的对象,您可以使用自己的存根来动态替换所有方法,这些存根执行前期工作,调用原始方法然后进行后期工作。

这样的事情会起作用:

function overideMethods(obj) {
    // can pass either an instantiated object (hooks existing methods on the object)
    //    or a function constructor (hooks methods in the prototype)
    if (typeof obj === "function") {
        obj = obj.prototype;
    }
    for (var prop in obj) {
        if (typeof obj[prop] === "function") {
            (function(origMethod) {
                obj[prop] = function() {
                    var retVal, args;

                    // do your pre-work here

                    // make copy of args passed to this method
                    args = Array.prototype.slice.call(arguments, 0);

                    // call original method with proper args
                    retVal = origMethod.apply(this, args);

                    // do your post-work here

                    return retVal;
                };
            })(obj[prop]);
        }
    }
}

工作演示:http://jsfiddle.net/jfriend00/7LzQj/


现在可以将此函数传递给对象或构造函数。如果传递一个对象,它将挂钩该对象上的现有可枚举方法。如果你传递一个构造函数,它将挂钩构造函数原型上的方法。这允许您为整个构造函数(预先)创建的所有对象设置挂钩,或者只挂钩单个对象。


如果您的对象动态地添加方法,无论是在构造函数中还是在对象生命周期的后期,并且您希望这些方法被挂钩,那么您需要在添加这些方法之后在对象上调用overideMethods() - 您将无法在构造函数上调用它。

答案 1 :(得分:1)

这是一个使用函数装饰器的可能解决方案。如果你有像Underscore这样的东西你可以修改一下代码,但我假设你没有。

装饰器是一个高阶函数,它返回另一个函数的修改版本。在某些情况下,装饰器是一种更安全的猴子修补方法,但这完全取决于您的需求。

以下是演示:http://jsbin.com/ApaLAVab/1/edit

function compose(f, g) {
  return function() {
    return f(g.apply(this, arguments));
  };
}

function before(fn) {
  return function() {
    console.log('before'); // code before method
    fn.apply(this, arguments);
  };
}

function after(fn) {
  return function() {
    fn.apply(this, arguments);
    console.log('after'); // code after method
  };
}

var run = compose(before, after);

function A() {}

A.prototype = {
  say: run(function(name) { // decorate method
    console.log('Hello '+ name);
  })
};

var a = new A();
a.say('Peter');
//^ before
//  Hello Peter
//  after

答案 2 :(得分:0)

您也可以将其添加到构造函数中,因此您不必手动运行它:

function SimpleClass(){   
    this.overideMethods();
}

SimpleClass.prototype.overideMethods = function() {
    var obj = this;
    for (var prop in obj) {
        if (typeof obj[prop] === "function") {
            console.log(prop);
            (function(origMethod) {
                obj[prop] = function() {
                    var retVal, args;
                    // do your pre-work here
                    alert("before function call");

                    // make copy of args passed to this method
                    args = Array.prototype.slice.call(arguments, 0);

                    // call original method with proper args
                    retVal = origMethod.apply(this, args);

                    // do your post-work here
                    alert("after function call");

                    return retVal;
                };
            })(obj[prop]);
        }
    }
}

SimpleClass.prototype.testFn = function(){
    alert("In the function.");
};

var testObj = new SimpleClass();
testObj.testFn();

工作示例:http://jsfiddle.net/awesomepeter/wvxAd/1/ 归功于jfriend00,我想做同样的事情,因为他来得有点太晚了;)所以我只是复制了他的答案并改进了。