Javascript: расширение функции
основная причина, почему я хочу это, что я хочу, чтобы расширить мою функцию инициализации.
что-то вроде этого:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
поэтому я хочу расширить функцию, как я расширяю класс в PHP.
и я хотел бы расширить его из других файлов тоже, так что, например, у меня есть исходная функция init в main.js
и расширенная функция в extended.js
.
5 ответов:
С более широким представлением о том, что вы на самом деле пытаетесь сделать, и контекст, в котором вы это делаете, я уверен, что мы могли бы дать вам лучший ответ, чем литерал ответ на ваш вопрос.
но вот буквальный ответ:
если вы назначаете эти функции какому-то свойству где-то, вы можете обернуть исходную функцию и поместить свою замену в свойство вместо этого:
// 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
анонимный объект или литерал. Вы можете написать его намного компактнее, если хотите иметь анонимные функции, но я не очень люблю анонимные функции.)
есть несколько способов сделать это, это зависит от того, какова ваша цель, если вы просто хотите выполнить функцию, а также и в том же контексте, вы можете использовать
.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(); };
другие методы великолепны, но они не сохраняют никаких функций прототипа, прикрепленных к init. Чтобы обойти это, вы можете сделать следующее (вдохновленный сообщением от Ника Крейвера).
(function () { var old_prototype = init.prototype; var old_init = init; init = function () { old_init.apply(this, arguments); // Do something extra }; init.prototype = old_prototype; }) ();
другой вариант может быть:
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 );
использовать extendFunction.js
init = extendFunction(init, function(args) { doSomethingHereToo(); });
но в вашем конкретном случае, проще расширить глобальную функцию onload:
extendFunction('onload', function(args) { doSomethingHereToo(); });
мне на самом деле очень нравится ваш вопрос, это заставляет меня думать о различных случаях использования.
для событий javascript вы действительно хотите добавлять и удалять обработчики - но для extendFunction, как вы могли бы позже удалить функциональность? Я мог бы легко добавить .верните метод к расширенным функциям, поэтому
init = init.revert()
вернет исходную функцию. Очевидно, что это может привести к некоторому довольно плохому коду, но, возможно, это позволит вам что-то сделать, не касаясь чужой части кодовой базы.