"取消重新定义“;谷歌浏览器's控制台对象

"Un-redefining" Google Chrome's console Object

本文关键字:谷歌浏览器 对象 控制台 取消 quot 新定义 定义      更新时间:2023-09-26

我正在处理一个系统,在该系统中,以下Javascript代码(我无法控制)正在页面的早期执行

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() {}
}

这段代码似乎用于创建一个模拟console对象,以防止在没有javascript控制台的环境中出现javascript错误。这是伟大的,除了它还阻止谷歌Chrome的控制台运行。条件显式检查firebug,但仅限于

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

那么,有没有办法告诉Chrome的调试器重新初始化其控制台对象?也就是说,用通俗的英语告诉Chrome

嘿,你知道当你加载一个页面并定义一个控制台对象供我使用吗?再次执行此操作,这样我们就可以覆盖用户空间中的某个人所做的操作。

我意识到我可以做一些类似的事情

console.firebug = "faketrue";

并捕获了条件,但我在系统中受到限制,在上述控制台重新定义命中之前无法添加javascript。换句话说,不,我不能只在头的开头添加一点javascript代码。

我相信您可以通过iframe注入来实现这一点,然后复制iframe的控制台对象:

<script type="text/javascript">
console = {};
try {
    console.log('1');
} catch(e){
    alert('No console');
}
</script>
<iframe id="text"></iframe>
<script type="text/javascript">
console = window.frames[0].console;
try {
    console.log('test');
} catch(e){
    alert('No console');
}
</script>

http://jsfiddle.net/nmY6k/

请注意,这只是一个概念应该起作用的演示。

编辑

使用纯JS iframe:

<script type="text/javascript">
console = {};
try {
    console.log('1');
} catch(e){
    alert('No console');
}
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
console = window.frames[0].console;
try {
    console.log('test');
} catch(e){
    alert('No console');
}
</script>

http://jsfiddle.net/nmY6k/1/

编辑

当然,如果之后需要删除iframe元素:

<script type="text/javascript">
console = {};
try {
    console.log('1');
} catch(e){
    alert('No console');
}
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
console = window.frames[0].console;
try {
    console.log('test');
} catch(e){
    alert('No console');
}
console.log(typeof window.frames);
document.body.removeChild(iframe);
console.log(typeof window.frames);
</script>

在Google Chrome中,删除console对象有效:

<script>
window.console = {};
delete console;
console.log('still works');
</script>

然而,这在Firefox 4中似乎不起作用。不过,这只是一个开始。

这似乎有效:

iframe = document.createElement('iframe');
document.body.appendChild(iframe);
console = iframe.contentWindow.console;

但是,看起来您无法删除iframe

您可以按照上面的建议编写一个非常基本的用户脚本来分配控制台。然后进入该用户脚本的manifest.json,并更改run_at设置(请参见http://code.google.com/chrome/extensions/content_scripts.html)到document_start。这将使得用户脚本现在在运行任何页面脚本之前运行,所以在控制台被搞砸之前。

编辑

事实上,我注意到http://blog.chromium.org/2011/07/chrome-extensions-now-with-more.htmlchrome现在也支持@run-at,所以您可以设置它,甚至不必直接使用manifest.json。他们有一个使用@run at的示例脚本,位于document_starthttp://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/userscript-runat/runat.user.js?view=markup

你不能把你自己的脚本直接放在html的顶部吗?

<script ...>
    if (console) { window.cache_console = console; }
</script>
</head>
<body>
... html ...
<script>
    window.console = window.cache_console;
</script>
</body>
</html>

你不可能比头脑清醒来得更早。

假设你担心的原因是你想在开发时正常使用控制台,你可以创建一个简单的chrome扩展,定义console.firebug,这样条件就会被评估为false。这样,您就不必担心使用其他框架的控制台对象可能会产生任何潜在的古怪行为,也不必担心在开发/部署时重复插入和删除黑客。

下面是我根据前面的答案编写的一个方法。它有一些额外的逻辑,因此您可以多次调用它,而无需重新创建iframe。

function fixConsole() {
    var iframe;
    if(!(iframe = document.getElementById('fixConsole'))) {
        iframe = document.createElement('iframe');
        iframe.id = 'fixConsole';
        document.body.appendChild(iframe);
    }
    delete console;    
    console = iframe.contentWindow.console;
};

我预计,在最初重新定义console的代码是自修复的情况下,需要多次调用fixConsole