如何在JavaScript中扩展一个方法?

3
我希望为一个方法添加额外的功能,比如说:
console.log()

所以原始的“log”功能保留下来了,我可以让它做一些新的事情。这种可能吗?我读了一些关于使用原型的文章,但还没有完全理解。
非常感谢。

1
就像这样,你可以向对象ADD(添加)一些内容,但不能修改已经存在的内容。你可以向控制台对象添加log2(),但不能修改已经存在的log()。 - friendzis
fcombine 允许您组合函数并返回一个新的函数。 - Raynos
5个回答

2

这非常简单。如果你想让你的新的 log 方法取代旧的 log 方法,只需要像这样做:

console._log = console.log; // just backing up old log method
console.log = function(){
    console._log(arguments);
    alert("I'm doing something else here");     
}
console.log(console);

更新:

所有提供的解决方案,包括我的,都不能完美地重现 @TomBates 所述的日志行为。输出不同是因为参数被包装在对象中记录,而不是单独传递。我找到唯一可以重现旧日志和扩展功能行为的方法就是这样:

    console.log(window, this, console); // old log in action

console._log = console.log; // just backing up old log method
console.log = function(){
    var args_string = '';
    for(i in arguments){
        if(arguments.hasOwnProperty(i)){
            args_string += 'arguments['+ i + ']';
            if(i != arguments.length - 1){
                args_string += ',';
            } 
        }
    }
    var expression = 'console._log(' + args_string + ');';
    eval(expression);

    alert("I'm doing something else here"); 
    // your dazzling method extension here   
}

console.log(window, this, console); //new log in action

虽然不太优雅,但达到了预期的效果。现在旧日志和新日志的输出结果是相同的。


修正了代码,并向新的控制台方法添加了参数,使其与“旧”方法一样有用。 - marcio
你刚刚破坏了 console.log.length - Raynos
我猜console.log.length必须保持完整,以便一些测试套件能够按预期工作,因此似乎很重要将其保留原样,就像@Deeptechtons在他的答案中聪明地做的那样。 - marcio
感谢大家的回答。@marcioAlmada:这个解决方案几乎可以工作,但原始行为是不同的。例如,在使用此解决方案之前/之后记录jquery元素,您将看到日志行为的差异。(无论是Firebug还是Webkit上的Web Inspector) - Tom Bates
是的,这是因为 arguments 对象包装了函数参数并干扰了日志输出。看一下更新后的答案,它有一个新的更好的解决方案(不太优雅)。 - marcio

1

由于JavaScript是可调用的面向对象语言,您可以这样做:

console._log_without_my_extension = console.log
console.log = function() { console._log_without_my_extension(); .... }

例如。


你的 console._log_without_my_extension() 需要接收参数才能够继续发挥作用。 - marcio
是的,当然他需要接收并传递任何他所需的参数! - Marian Theisen

0

据我所知,JS中的扩展不是默认功能,唯一的方法类似于以下内容:

var oldLog = console.log;
console.log = function(){
    //doStuff
    oldLog(arguments);
    //doStuff
}

0
你只能在对象已经拥有原型的情况下使用prototype属性,console不是其中之一。请使用其他答案。阅读以下内容以了解关于prototype的知识:

http://phrogz.net/js/classes/ExtendingJavaScriptObjectsAndClasses.html

顺便说一下:除非您像其他答案中建议的那样制作包装器,否则无法扩展函数。

-1
如果您严格地尝试扩展Firebug中的控制台,它没有原型,因此您可以放心这样做。
console.logMe = function(){console.log(arguments)};
console.logMe("welcome to SO");

更新

由于我曾经错误地理解了问题,现在我想进行更正。OP 希望将基本方法抽象化并覆盖基本方法。(看起来我说的废话,请查看下面的代码)

function myConsole() {}

myConsole.prototype = {
    _log: console.log,
    Log: function () {
        this._log(arguments)
    }
};

使用其他方法时,您将不得不一遍又一遍地执行它。但是在这里,您创建的每个实例都将具有扩展方法和自己内置的实现。

用法

var x = new myConsole();
x.Log("Hi this is Deeptechtons");

所有给我点踩的人,能否告诉我下为什么呢?谢谢。 - Deeptechtons
不是我,而是问题在于扩展一个方法,而不是创建一个新的方法。 - OptimusCrime
我给它点了个踩,但是糟糕的是,你的代码其实没问题,我评价错了!(我匆忙看了一眼,以为它有另一个答案的错误)。我试图取消投票,但应用程序说除非回答被编辑,否则我无法取消踩(时间过去太久了)。你能做一个小修改让我可以取消踩吗?真的很抱歉。 - marcio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接