Javascript: Extend a Function
Głównym powodem, dla którego tego chcę, jest to, że chcę rozszerzyć moją funkcję initialize.
Coś takiego:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
Więc chcę rozszerzyć funkcję tak jak rozszerzam klasę w PHP.
I chciałbym rozszerzyć ją również z innych plików, więc na przykład mam oryginalną funkcję init w main.js
i rozszerzoną funkcję w extended.js
.
5 answers
Z szerszym spojrzeniem na to, co naprawdę próbujesz zrobić i kontekst, w którym to robisz, jestem pewien, że możemy dać ci lepszą odpowiedź niż literalna odpowiedź na twoje pytanie.
Ale oto dosłowna odpowiedź:
Jeśli przypisujesz te funkcje do jakiejś właściwości, możesz zawinąć oryginalną funkcję i zamiast tego umieścić zamiennik na właściwości:
// 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);
Jeśli twoje funkcje nie są już na obiekcie, prawdopodobnie chcesz je umieścić tam, aby ułatwić powyższe. Na przykład:
// 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();
}
})();
Ale są na to lepsze sposoby. Jak na przykład zapewnienie sposobu rejestracji init
funkcji.
// 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;
})();
(Wiele z powyższych można by napisać nieco bardziej zwięźle, ale chciałem użyć jasnych nazw, takich jak publicSymbols
, a nie moich zwykłych pubs
lub anonimowych dosłownych obiektów. Możesz pisać o wiele bardziej zwięźle, jeśli chcesz mieć funkcje anonimowe, ale nie dbam o anonimowość funkcje .)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-02 13:36:48
Istnieje kilka sposobów, aby to zrobić, to zależy, jaki jest twój cel, jeśli chcesz po prostu wykonać funkcję, a w tym samym kontekście, możesz użyć .apply()
:
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
Jeśli chcesz zastąpić go nowszym init
, będzie wyglądał tak:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-02 13:07:15
Inne metody są świetne, ale nie zachowują żadnych prototypowych funkcji dołączonych do init. Aby to obejść, możesz wykonać następujące czynności (zainspirowane postem od Nicka Cravera).
(function () {
var old_prototype = init.prototype;
var old_init = init;
init = function () {
old_init.apply(this, arguments);
// Do something extra
};
init.prototype = old_prototype;
}) ();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 09:49:50
Inną opcją może być:
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 );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-06 15:20:00
Użyj extendFunction.js
init = extendFunction(init, function(args) {
doSomethingHereToo();
});
Ale w twoim konkretnym przypadku łatwiej jest rozszerzyć globalną funkcję onload:
extendFunction('onload', function(args) {
doSomethingHereToo();
});
Naprawdę podoba mi się Twoje pytanie, to sprawia, że myślę o różnych przypadkach użycia.
Dla zdarzeń javascript, naprawdę chcesz dodawać i usuwać programy obsługi - ale dla funkcji extendFunction, jak możesz później usunąć funkcjonalność ? Mogę z łatwością dodać .przywróci metodę do funkcji rozszerzonych, więc init = init.revert()
zwróci oryginał funkcja. Oczywiście może to prowadzić do jakiegoś dość złego kodu, ale być może Pozwala to zrobić coś bez dotykania zagranicznej części kodu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-04 05:34:58