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()
вернет исходную функцию. Очевидно, это может привести к довольно плохому коду, но, возможно, это позволит вам что-то сделать, не касаясь иностранной части кодовой базы.