Ada*_*dam 85 javascript function extend
我想要它的主要原因是我想扩展我的初始化函数.
像这样的东西:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
Run Code Online (Sandbox Code Playgroud)
所以我想扩展一个函数,比如我在PHP中扩展一个类.
我也想从其他文件扩展它,所以例如我有原始的init函数main.js和扩展函数extended.js.
T.J*_*der 93
通过更广泛地了解您实际上要做的事情以及您正在做的事情,我相信我们可以给您一个比您的问题的字面答案更好的答案.
但这是一个字面答案:
如果您将这些函数分配给某个属性,则可以包装原始函数并将替换项放在属性上:
// 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);
Run Code Online (Sandbox Code Playgroud)
如果您的功能尚未出现在某个对象上,您可能希望将它们放在那里以方便上述操作.例如:
// 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();
}
})();
Run Code Online (Sandbox Code Playgroud)
但也有这样的更好的方法来做到这一点.例如,提供一种注册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;
})();
Run Code Online (Sandbox Code Playgroud)
(上面的大部分内容可以写得更紧凑,但我想使用清晰的名称,publicSymbols而不是我的通常pubs或匿名对象文字.如果你想要匿名函数,你可以写得更紧凑,但我不是非常关心匿名函数.)
Nic*_*ver 61
有几种方法可以解决这个问题,这取决于你的目的是什么,如果你只想在同一个环境中执行该函数,你可以使用.apply():
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
Run Code Online (Sandbox Code Playgroud)
如果你想用更新的替换它init,它看起来像这样:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
Run Code Online (Sandbox Code Playgroud)
The idea of function extensions comes from functional paradigm, which is natively supported since ES6:
function init(){
doSomething();
}
// extend.js
init = (f => u => { f(u)
doSomethingHereToo();
})(init);
init();
Run Code Online (Sandbox Code Playgroud)
As per @TJCrowder's concern about stack dump, the browsers handle the situation much better today. If you save this code into test.html and run it, you get
test.html:3 Uncaught ReferenceError: doSomething is not defined
at init (test.html:3)
at test.html:8
at test.html:12
Run Code Online (Sandbox Code Playgroud)
Line 12: the init call, Line 8: the init extension, Line 3: the undefined doSomething() call.
Note: Much respect to veteran T.J. Crowder, who kindly answered my question many years ago, when I was a newbie. After the years, I still remember the respectfull attitude and I try to follow the good example.
其他方法很棒,但它们不保留任何附加到 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;
}) ();
Run Code Online (Sandbox Code Playgroud)
另一种选择可能是:
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 );
Run Code Online (Sandbox Code Playgroud)