web-dev-qa-db-ja.com

Javascript:関数を拡張する

私がそれを望む主な理由は、初期化関数を拡張したいからです。

このようなもの:

// main.js

window.onload = init();
function init(){
     doSomething();
}

// extend.js

function extends init(){
    doSomethingHereToo();
}

したがって、PHPでクラスを拡張するように関数を拡張したいと思います。

また、他のファイルからも拡張したいので、たとえば、main.jsに元のinit関数があり、extended.jsに拡張関数があります。

83
Adam

あなたが実際に何をしようとしているのか、あなたがそれをしているコンテキストの広い視野で、literalよりも良い答えを与えることができると確信していますあなたの質問に答えてください。

しかし、これは文字通りの答えです。

これらの関数をどこかのプロパティに割り当てる場合、元の関数をラップして、代わりにプロパティに置換を置くことができます。

// Original code in main.js
var theProperty = init;

function init(){
     doSomething();
}

// Extending it by replacing and wrapping, in extended.js
theProperty = (function(old) {
    function extendsInit() {
        old();
        doSomething();
    }

    return extendsInit;
})(theProperty);

関数がまだオブジェクト上にない場合は、おそらく上記を容易にするためにそこに配置する必要があります。例えば:

// In main.js
var MyLibrary = (function() {
    var publicSymbols = {};

    publicSymbols.init = init;
    function init() {
    }

    return publicSymbols;
})();

// In extended.js
(function() {
    var oldInit = MyLibrary.init;
    MyLibrary.init = extendedInit;
    function extendedInit() {
        oldInit.apply(MyLibrary); // Use #apply in case `init` uses `this`
        doSomething();
    }
})();

しかし、suchより良い方法があります。たとえば、init関数を登録する手段を提供します。

// In main.js
var MyLibrary = (function() {
    var publicSymbols = {},
        initfunctions = [];

    publicSymbols.init = init;
    function init() {
        var funcs = initFunctions;

        initFunctions = undefined;

        for (index = 0; index < funcs.length; ++index) {
            try { funcs[index](); } catch (e) { }
        }
    }

    publicSymbols.addInitFunction = addInitFunction;
    function addInitFunction(f) {
        if (initFunctions) {
            // Init hasn't run yet, rememeber it
            initFunctions.Push(f);
        }
        else {
            // `init` has already run, call it almost immediately
            // but *asynchronously* (so the caller never sees the
            // call synchronously)
            setTimeout(f, 0);
        }
    }

    return publicSymbols;
})();

(上記の多くはもう少し簡潔に書くことができましたが、私の通常のpublicSymbolsや匿名オブジェクトリテラルではなく、pubsのような明確な名前を使用したかったのです。匿名関数を使いたい場合はもっとコンパクトになりますが、 匿名関数はあまり気にしません 。)

91
T.J. Crowder

これについてはいくつかの方法があります。目的によって異なります。関数を同じコンテキストで実行したい場合は、 .apply() を使用できます。

function init(){
  doSomething();
}
function myFunc(){
  init.apply(this, arguments);
  doSomethingHereToo();
}

新しいinitに置き換えたい場合は、次のようになります。

function init(){
  doSomething();
}
//anytime later
var old_init = init;
init = function() {
  old_init.apply(this, arguments);
  doSomethingHereToo();
};
60
Nick Craver

他のメソッドは優れていますが、initにアタッチされたプロトタイプ関数は保持されません。これを回避するために、次のことができます(Nick Craverの投稿に触発された)。

(function () {
    var old_prototype = init.prototype;
    var old_init = init;
    init = function () {
        old_init.apply(this, arguments);
        // Do something extra
    };
    init.prototype = old_prototype;
}) ();
4
Ally

別のオプションは次のとおりです。

var initial = function() {
    console.log( 'initial function!' );
}

var iWantToExecuteThisOneToo = function () {
    console.log( 'the other function that i wanted to execute!' );
}

function extendFunction( oldOne, newOne ) {
    return (function() {
        oldOne();
        newOne();
    })();
}

var extendedFunction = extendFunction( initial, iWantToExecuteThisOneToo );
3
Sérgio

これは非常にシンプルで簡単です。コードを見てください。 javascript拡張の背後にある基本概念を理解してください。

まず、javascript関数を拡張しましょう。

function Base(props) {
    const _props = props
    this.getProps = () => _props

    // We can make method private by not binding it to this object. 
    // Hence it is not exposed when we return this.
    const privateMethod = () => "do internal stuff" 

    return this
}

次の方法で子関数を作成することにより、この関数を拡張できます

function Child(props) {
    const parent = Base(props)
    this.getMessage = () => `Message is ${parent.getProps()}`;

    // You can remove the line below to extend as in private inheritance, 
    // not exposing parent function properties and method.
    this.prototype = parent
    return this
}

これで、次のように子関数を使用できます。

let childObject = Child("Secret Message")
console.log(childObject.getMessage())     // logs "Message is Secret Message"
console.log(childObject.getProps())       // logs "Secret Message"

このようにJavascriptクラスを拡張することにより、Javascript関数を作成することもできます。

class BaseClass {
    constructor(props) {
        this.props = props
        // You can remove the line below to make getProps method private. 
        // As it will not be binded to this, but let it be
        this.getProps = this.getProps.bind(this)
    }

    getProps() {
        return this.props
    }
}

このようなChild関数でこのクラスを拡張してみましょう。

function Child(props) {
    let parent = new BaseClass(props)
    const getMessage = () => `Message is ${parent.getProps()}`;
    return { ...parent, getMessage} // I have used spread operator. 
}

繰り返しますが、次のように子関数を使用して同様の結果を得ることができます。

let childObject = Child("Secret Message")
console.log(childObject.getMessage())     // logs "Message is Secret Message"
console.log(childObject.getProps())       // logs "Secret Message"

Javascriptは非常に簡単な言語です。ほとんど何でもできます。ハッピーJavaScripting ...私はあなたのケースで使用するアイデアをあなたに与えることができたと思います。

0
Market Queue