恢复 console.log()

69

由于原型框架(或其他JavaScript代码)与 Magento 一起发布,所以我无法调试任何内容。在JavaScript控制台中输入console,我会得到以下输出:

> console
Object
assert: function () {}
count: function () {}
debug: function () {}
dir: function () {}
dirxml: function () {}
error: function () {}
group: function () {}
groupEnd: function () {}
info: function () {}
log: function () {}
profile: function () {}
profileEnd: function () {}
time: function () {}
timeEnd: function () {}
trace: function () {}
warn: function () {}
我在Linux上使用的是Google Chrome版本13.0.782.112。 Prototype JavaScript框架的版本为1.6.0.3。 有没有快速解决这个问题的方法?

请查看 https://dev59.com/QWw05IYBdhLWcg3wsz7N - Reto Aebersold
3
看起来Magento有一个开放问题,涉及到这个链接:http://www.magentocommerce.com/bug-tracking/issue/?issue=11312 - RoccoC5
是的,看起来我有这个问题,但我不打算更改Magento代码,对于dev来说,我接受已接受的解决方案。 - s3v3n
8个回答

115

由于原始控制台在window.console对象中,尝试从iframe中恢复window.console

var i = document.createElement('iframe');
i.style.display = 'none';
document.body.appendChild(i);
window.console = i.contentWindow.console;
// with Chrome 60+ don't remove the child node
// i.parentNode.removeChild(i);

在Chrome 14上可以正常工作。


8
任何想要使用这个的人,请记得在使用后自行清理干净。即:i.parentNode.removeChild(i); - Seth Holladay
11
这个答案在目前版本的Chrome(52+)中实际上有效,而被接受的答案则无效。 - S.B.
1
@NickCoad 在最后的 i.parentNode.removeChild(i) 之后它仍然能正常工作,对吗? - Grzegorz Rożniecki
10
我正在使用Chrome 63 (Canary),这个答案可以使用,但是只有在没有 i.parentNode.removeChild(i); 这一行的情况下。 - Vortexfive
2
只有在使用控制台完成后,才能清理自己的东西!没有子级将无法正常工作。 - Jānis Elmeris
显示剩余6条评论

49
例如,
delete console.log

还会恢复 console.log

console.log = null;
console.log;         // null

delete console.log;
console.log;         // function log() { [native code] }

1
是的!这甚至更好!这就是我喜欢stackoverflow的原因:D - s3v3n
9
尝试使用 delete window.console,我在 Chrome 30.x 中这样做有效。 - OneOfOne
29
在Chrome 52中不再起作用。可以在Twitter上进行测试,例如:将console.log改为function() {},删除掉console.logwindow.console.log都只会将其删除,而不会恢复原来的行为。 - S.B.
2
可以确认……在新版的Chrome中无法工作。我正在扩展OwnCloud,但他们移除了console.log(什么鬼?) - MilMike
2
这里有一个小技巧,可以帮助解决Chrome在使用delete console.log时无法恢复本地日志功能的问题... 如果您愿意安装(或已经安装)TamperMonkey,则只需要一个简单的脚本... setTimeout(() => { unsafeWindow.console = window.console; }, 2000); Tampermonkey脚本会得到它们自己的window对象副本,所以您只需要在延迟后恢复原始控制台对象即可。根据需要进行调整...(确保删除默认的// @grant none)。 - Michael Bray
显示剩余3条评论

12

Magento在/js/varien/js.js中有以下代码-将其注释掉,它就可以工作。

if (!("console" in window) || !("firebug" in console))
{
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

    window.console = {};
    for (var i = 0; i < names.length; ++i)
        window.console[names[i]] = function() {}
}

12

如果有人遇到相同的情况,请注意以下事项。

我没有回复Xaerxess的原始答案,因为我没有足够的声望来这样做。

看起来那是正确的答案,但出于某些原因,我注意到有时它在我的软件中工作,有时则不行...

所以,在运行脚本之前,我尝试完全删除它,看起来一切都正常100%的时间运行。

if (!("console" in window) || !("firebug" in console))
{

  console.log = null;
  console.log;         // null

  delete console.log;

  // Original by Xaerxess
  var i = document.createElement('iframe');
  i.style.display = 'none';
  document.body.appendChild(i);
  window.console = i.contentWindow.console;

}

感谢大家。

现在这不应该成为被接受的答案吗?因为原来被接受的答案在最新的Chrome或Firefox上已经不再起作用了。 - Rohan
这对我有用。仅仅执行 delete console.log 并没有起作用,所以这应该是被接受的答案。 - OG Sean

6

delete window.console可以在Firefox和Chrome中恢复原始的console对象。

这是怎么做到的呢?window是一个托管对象,通常它是在所有实例之间使用共同原型来实现的(在浏览器中有许多选项卡)。

一些愚蠢的外部库/框架的开发人员(或Firebug等)覆盖了window实例的属性控制台,但它并没有破坏window.prototype。通过delete操作符,我们将从console.*方法返回到原型代码。


3
function restoreConsole() {
  // Create an iframe for start a new console session
  var iframe = document.createElement('iframe');
  // Hide iframe
  iframe.style.display = 'none';
  // Inject iframe on body document
  document.body.appendChild(iframe);
  // Reassign the global variable console with the new console session of the iframe 
  console = iframe.contentWindow.console;
  window.console = console;
  // Don't remove the iframe or console session will be closed
}

已在Chrome 71和Firefox 65上测试


这与@Xaerxess的答案相同,如果您查看他的答案评论,您会发现针对新版Chrome的警告...您可以只点赞他的答案并点赞评论,无需重复。 - balexandre
@balexandre 不同,因为这个函数不会删除子元素,如果你不删除子元素,它仍然可以工作,否则控制台将不会打印任何内容 :) - Marco Cesarato
仅仅因为你改变了一行代码,就不应该得到一个新的答案……Stackoverflow 不是用来衡量谁写出更好的代码,而是帮助下一个人快速获得正确答案的。 - balexandre

2

在脚本的最开始将原始的console引用保存到一个变量中,然后使用这个引用或者重新定义console指向捕获的值。

例子:

var c = window.console;

window.console = {
    log :function(str) {
        alert(str);
    }
}

// alerts hello
console.log("hello");

// logs to the console
c.log("hello");

当然我可以这样做,只需要在所有代码之前注入一些JS,我相信这种解决方案会奏效,但是我想要一个更快速的解决问题的方法。无论如何,谢谢。 - s3v3n

-1
这个问题中提供的解决方案在新浏览器中不再正确地解决这个问题。唯一(勉强)可行的方法是按照@Xaerxess所说从<iframe> 中获取控制台。
我编写了一个用户脚本来保护控制台不被覆盖。它不会破坏任何覆盖控制台的工具 - 它调用覆盖和原始方法。当然,它也可以被包含在网页中。
// ==UserScript==
// @name        Protect console
// @namespace   util
// @description Protect console methods from being overriden
// @include     *
// @version     1
// @grant       none
// @run-at      document-start
// ==/UserScript==
{

    /**
      * This object contains new methods assigned to console.
      * @type {{[x:string]:Function}} **/
    const consoleOverridenValues = {};
    /**
      * This object contains original methods copied from the console object
      * @type {{[x:string]:Function}} **/
    const originalConsole = {};
    window.originalConsole = originalConsole;
    // This is the original console object taken from window object
    const originalConsoleObject = console;
    /**
     * 
     * @param {string} name
     */
    function protectConsoleEntry(name) {
        const protectorSetter = function (newValue) {
            originalConsole.warn("Someone tried to change console." + name + " to ", newValue);
            consoleOverridenValues[name] = function () {
                /// call original console first
                originalConsole[name].apply(originalConsoleObject, arguments);
                if (typeof newValue == "function") {
                    /// call inherited console
                    newValue.apply(window.console, arguments);
                }
            }
        }
        const getter = function () {
            if (consoleOverridenValues[name])
                return consoleOverridenValues[name];
            else
                return originalConsole[name];
        }
        Object.defineProperty(console, name, {
            enumerable: true,
            configurable: false,
            get: getter,
            set: protectorSetter
        });
    }

    /*
     *** This section contains window.console protection
     *** It mirrors any properties of newly assigned values
     *** to the overridenConsoleValues
     *** so that they can be used properly
    */

    /** 
      * This is any new object assigned to window.console
      * @type {Object} **/
    var consoleOverridenObject = null;
    /// Separate boolean is used instead
    /// of checking consoleOverridenObject == null
    /// This allows null and undefined to be assigned with 
    /// expected result
    var consoleIsOverriden = false;

    for (var i in console) {
        originalConsole[i] = console[i];
        protectConsoleEntry(i);
    }

    Object.defineProperty(window, "console", {
        /// always returns the original console object
       /// get: function () { return consoleIsOverriden ? consoleOverridenObject : originalConsoleObject; },
        get: function () { return originalConsoleObject; },
        set: function (val) {
            originalConsole.log("Somebody tried to override window.console. I blocked this attempt."
                + " However the emulation is not perfect in this case because: \n"
                + "     window.console = myObject;\n"
                + "     window.console == myObject\n"
                + "returns false."
            )
            consoleIsOverriden = true;
            consoleOverridenObject = val;

            for (let propertyName in val) {
                consoleOverridenValues[propertyName] = val[propertyName];
            }
            return console;
        },
    });
}

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