Javascript:扩展功能

时间:2011-01-02 12:48:26

标签: javascript function extend

我想要它的主要原因是我想扩展我的初始化函数。

这样的事情:

// main.js

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

// extend.js

function extends init(){
    doSomethingHereToo();
}

所以我想扩展一个函数,比如我在PHP中扩展一个类。

我也想从其他文件中扩展它,所以例如我在main.js中有原始的init函数,在extended.js中有扩展函数。

6 个答案:

答案 0 :(得分:90)

通过更广泛地了解您实际上要做的事情以及您正在做的事情,我相信我们可以给您一个比 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();
    }
})();

但是有这样的更好的方法来做到这一点。例如,提供一种注册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或匿名对象文字。你可以写它如果你想拥有匿名函数,可以更紧凑,但I don't much care for anonymous functions。)

答案 1 :(得分:58)

有几种方法可以解决这个问题,这取决于你的目的是什么,如果你只是想在同一个环境中执行这个功能,你可以使用.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();
};

答案 2 :(得分:3)

另一种选择可能是:

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 :(得分:1)

2017+解决方案

功能扩展的思想来自功能范式,自ES6以来一直受本机支持:

function init(){
    doSomething();
}

// extend.js

init = (f => u => { f(u)
    doSomethingHereToo();
})(init);

init();

根据@TJCrowder对堆栈转储的关注,今天的浏览器处理情况要好得多。如果将此代码保存到 test.html 中并运行它,则会得到

test.html:3 Uncaught ReferenceError: doSomething is not defined
    at init (test.html:3)
    at test.html:8
    at test.html:12

第12行:init调用,第8行:init扩展,第3行:未定义的doSomething()调用。

注意:非常尊重老将T.J.克劳德(Crowder),好多年前,当我还是新手时,他很乐意回答我的问题。多年之后,我仍然记得尊重的态度,并尝试效法榜样。

答案 4 :(得分:0)

这非常简单直接。看代码。尝试掌握javascript扩展背后的基本概念。

首先让我们扩展javascript功能。

:target-path "build/classes/main"

您可以通过以下方式创建子功能来扩展此功能

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
}

我们还可以通过扩展Javascript类来创建Javascript函数。

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

让我们使用此类的Child函数扩展此类,

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. 
}

JavaScript是非常简单的语言。我们几乎可以做任何事。 JavaScript编程愉快...希望我能给您一个思路,供您参考。

答案 5 :(得分:-2)

使用extendFunction.js

init = extendFunction(init, function(args) {
  doSomethingHereToo();
});

但在您的具体情况下,扩展全局onload函数更容易:

extendFunction('onload', function(args) {
  doSomethingHereToo();
});

我其实非常喜欢你的问题,这让我想到了不同的用例。

对于javascript事件,您确实想添加和删除处理程序 - 但对于extendFunction,您以后如何删除功能?我可以轻松地将.revert方法添加到扩展函数中,因此init = init.revert()将返回原始函数。显然这可能导致一些非常糟糕的代码,但也许它可以让你在不触及代码库的外来部分的情况下完成某些事情。