2

JavaScript 関数に対して AOP のような「前」機能を実行したいと考えています。

そこで、既存のソリューションを探して、jQuery の aop-plugin を見つけました。残念ながら、プラグインは指定された関数をラップするだけです。そのため、関数を拡張する前に元の関数を指すオブジェクトは、元の関数を引き続き指します。これらのオブジェクトから関数を呼び出すと、拡張されていないバージョンの関数が呼び出されます。

関数を他の関数でラップする代わりに、関数オブジェクト自体を変更したいので、以前の参照によって予期しない動作が発生することはありません。だから私はこのようなものを得ました:

(function(){}).constructor.prototype.before = function(beforeFunction){
    this.beforeFunction = beforeFunction;
};

/* some magic should happen here: enhance call? */

function logFoo() {
    console.log("Foo");
};
function logBar() {
    console.log("Bar");
};

logFoo(); // logs "Foo"

logFoo.before(logBar);

logFoo(); // should log "Bar", then "Foo"

問題は、強化された関数が呼び出されたときに beforeFunction を呼び出すにはどうすればよいかということです。

4

1 に答える 1

6

関数の本体、パラメーター、および参照環境は不変であるため、関数を拡張することはできず、新しい関数を作成することしかできません。

次のように、関数を最初から拡張可能にすることができます。

Function.prototype.enhanceable = function() {
    var original = this,
        enhanced = [],
        ret = function() {
            for( var i = 0; i < enhanced.length; ++i ) {
                enhanced[i].apply( this, arguments );
            }

            return original.apply( this, arguments );
        };

    ret.before = function( fn ) {
        enhanced.push( fn );
    };

    return ret;
};

それで:

var logFoo = function() {
     console.log( "foo" );
}.enhanceable();

var logBar = function() {
     console.log( "bar" );
};

logFoo(); //foo

logFoo.before( logBar );

logFoo(); //logs bar, then foo
于 2012-11-20T11:30:43.673 に答える