Javascript:扩展函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4578424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript: Extend a Function
提问by Adam
The main reason why I want it is that I want to extend my initialize function.
我想要它的主要原因是我想扩展我的初始化功能。
Something like this:
像这样的东西:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
So I want to extend a function like I extend a class in PHP.
所以我想扩展一个函数,就像我在 PHP 中扩展一个类一样。
And I would like to extend it from other files too, so for example I have the original init function in main.js
and the extended function in extended.js
.
而且我也想从其他文件中扩展它,例如,我main.js
在extended.js
.
回答by T.J. Crowder
With a wider view of what you're actually trying to do and the context in which you're doing it, I'm sure we could give you a better answer than the literalanswer to your question.
通过更广泛地了解您实际尝试做什么以及您在做什么的背景下,我相信我们可以为您提供比问题的字面答案更好的答案。
But here's a literal answer:
但这是一个字面的答案:
If you're assigning these functions to some property somewhere, you can wrap the original function and put your replacement on the property instead:
如果您将这些函数分配给某处的某个属性,则可以包装原始函数并将替换的函数放在该属性上:
// 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);
If your functions aren't already on an object, you'd probably want to put them there to facilitate the above. For instance:
如果您的函数还没有在对象上,您可能希望将它们放在那里以方便上述操作。例如:
// 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();
}
})();
But there are suchbetter ways to do that. Like for instance, providing a means of registering init
functions.
但也有这样的更好的方法来做到这一点。例如,提供一种注册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;
})();
(Much of the above could be written a bit more compactly, but I wanted to use clear names like publicSymbols
rather than my usual pubs
or anonymous object literal. You can write it a lot more compactly if you want to have anonymous functions, but I don't much care for anonymous functions.)
(上面的大部分内容可以写得更紧凑一些,但我想使用明确的名称,publicSymbols
而不是我通常的pubs
或匿名对象文字。如果你想拥有匿名函数,你可以写得更紧凑,但我不”不太关心匿名函数。)
回答by Nick Craver
There are several ways to go about this, it depends what your purpose is, if you just want to execute the function as well and in the same context, you can use .apply()
:
有几种方法可以解决这个问题,这取决于您的目的是什么,如果您只想在相同的上下文中执行该函数,您可以使用.apply()
:
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
If you want to replace it with a newer init
, it'd look like this:
如果你想用更新的替换它init
,它看起来像这样:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
回答by Ally
The other methods are great but they don't preserve any prototype functions attached to init. To get around that you can do the following (inspired by the post from Nick Craver).
其他方法很棒,但它们不保留任何附加到 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;
}) ();
回答by Sérgio
Another option could be:
另一种选择可能是:
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 );
回答by Market Queue
This is very simple and straight forward. Look at the code. Try to grasp the basic concept behind javascript extension.
这是非常简单和直接的。看代码。尝试掌握 javascript 扩展背后的基本概念。
First let us extend javascript function.
首先让我们扩展javascript函数。
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
}
You can extend this function by creating child function in following way
您可以通过以下方式创建子函数来扩展此函数
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
}
Now you can use Child function as follows,
现在您可以按如下方式使用 Child 函数,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
We can also create Javascript Function by extending Javascript classes, like this.
我们还可以通过扩展 Javascript 类来创建 Javascript 函数,就像这样。
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
}
}
Let us extend this class with Child function like this,
让我们像这样用 Child 函数扩展这个类,
function Child(props) {
let parent = new BaseClass(props)
const getMessage = () => `Message is ${parent.getProps()}`;
return { ...parent, getMessage} // I have used spread operator.
}
Again you can use Child function as follows to get similar result,
同样,您可以按如下方式使用 Child 函数来获得类似的结果,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
Javascript is very easy language. We can do almost anything. Happy JavaScripting... Hope I was able to give you an idea to use in your case.
Javascript 是一种非常简单的语言。我们几乎可以做任何事情。愉快的 JavaScripting ......希望我能给你一个想法来在你的情况下使用。
回答by Devin G Rhode
Use extendFunction.js
使用extendFunction.js
init = extendFunction(init, function(args) {
doSomethingHereToo();
});
But in your specific case, it's easier to extend the global onload function:
但在您的特定情况下,扩展全局 onload 功能更容易:
extendFunction('onload', function(args) {
doSomethingHereToo();
});
I actually really like your question, it's making me think about different use cases.
我真的很喜欢你的问题,它让我思考不同的用例。
For javascript events, you really want to add and remove handlers - but for extendFunction, how could you later removefunctionality? I could easily add a .revert method to extended functions, so init = init.revert()
would return the original function. Obviously this could lead to some pretty bad code, but perhaps it lets you get something done without touching a foreign part of the codebase.
对于 javascript 事件,您确实想添加和删除处理程序 - 但是对于 extendFunction,您以后如何删除功能?我可以轻松地向扩展函数添加一个 .revert 方法,因此init = init.revert()
会返回原始函数。显然,这可能会导致一些非常糟糕的代码,但也许它可以让您在不接触代码库的外部部分的情况下完成某些工作。