这个算是 Chrome only 其他的我没测试,也不想测试。因为我的控制台脚本仅仅在 Chrome 下加载。

如果你需要全平台,那么这肯定不是你需要的结果。

需求

其实我很早就想折腾这个了,但是,,因为懒,拖了很久,直到周末,我看到服务器上统计,发现流量翻了一倍,结果访问量还是一样的时候,我才下决心折腾。

知之为知之不知谷歌之

一开始,谷歌一番,发现有两种思路。

第一个是 sindresorhus 大神写的 devtools-detect,算是全平台兼容(除IE),但独立窗口打开的时候是检测不到的。

另一个是咱们国人 zswang 写的 jdetects,目测也是 Chrome only,当然我的灵感也来至于他。

虽然有两个现成的,但这都不是我满意的模式,于是乎就有了本次 Chrome 控制台环境探索之旅。

分析控制台环境

根据 zswangjdetects 得知,控制台会解析节点元素的 id 属性。

那么为什么会解析呢?或者他还做了什么处理呢?

打开浏览器,按 F12 打开 console 后输入 debugger 按回车,然后按两次 F11,OK 完成。

如果你的 Chrome 50 的话,映入眼帘的是密密麻麻的一大串压缩的字符,好在他们没 uglify,否则我就默默关了,也不会有这篇文章了。

点左下角 {} 格式化代码后,变的非常漂亮,但是没有注释了,我记得之前版本都是有注释的,更容易阅读。

大致预览下代码,最终定位到 660 行的 _describe 方法处,其他都不管我也不知道干嘛的,分析需要的代码即可。

// 用易懂的形式,描述各种对象方法,如正则,日期,node,数组,函数 等。
_describe: function(obj) {
if (this.isPrimitiveValue(obj)) // 如果是原始值不描述
return null; // 获取类型名包括 ArrayLike,但不是 Object.prototype.toString,有兴趣可以单独查看源码
var subtype = this._subtype(obj); if (subtype === "regexp") // 正则和日期输出 toString 后的结果。
return toString(obj);
if (subtype === "date")
return toString(obj); if (subtype === "node") { // dom 节点处理,这里是重点
// 获取节点名,text comment 等只有 nodeName
var description = obj.nodeName.toLowerCase();
switch (obj.nodeType) { // 节点类型
case 1: // Element 类型
description += obj.id ? "#" + obj.id : ""; // 获取元素 id
var className = obj.className; // 获取元素 class
description += (className && typeof className === "string") ? "." + className.trim().replace(/\s+/g, ".") : "";
break;
case 10: // DocumentType 类型
description = "<!DOCTYPE " + description + ">";
break;
}
return description;
} // 获取内部构造函数名,可能类似 Object.prototype.toString
var className = InjectedScriptHost.internalConstructorName(obj); // 类似数组的就输出 对象名[长度] 比如 Array[3], jQuery.fn.jQuery.init[2] 之类的
if (subtype === "array") {
if (typeof obj.length === "number")
className += "[" + obj.length + "]";
return className;
} if (typeof obj === "function") // 函数 toString
return toString(obj); if (isSymbol(obj)) { // Symbol 处理
try {
return (InjectedScriptHost.callFunction(Symbol.prototype.toString, obj)) || "Symbol";
} catch (e) {
return "Symbol";
}
} // 错误类型处理
if (InjectedScriptHost.subtype(obj) === "error") {
try {
var stack = obj.stack;
var message = obj.message && obj.message.length ? ": " + obj.message : "";
var firstCallFrame = /^\s+at\s/m.exec(stack);
var stackMessageEnd = firstCallFrame ? firstCallFrame.index : -1;
if (stackMessageEnd !== -1) {
var stackTrace = stack.substr(stackMessageEnd);
return className + message + "\n" + stackTrace;
}
return className + message;
} catch (e) {}
}
return className;
}

OK,代码挺简单的,看完基本就知道为什么 jdetects 可以检测控制台是否被打开了。

那么现在我们知道,其实完全可以借助 正则,日期,函数toString 实现,而且更简单,例如:

var re = /x/;
var i = 0;
console.log(re); re.toString = function () {
return '第 ' + (++i) + ' 次打开控制台';
};

简单又好用,也不需要定时器或 resize 事件监视,性能更是好到不用说。需要注意的是这里的 re.toString 必须在 console.log 之后定义,否则没打开控制台 toString 也会执行。

如果只是监听控制台打开,这个几行代码足以,但是我还没想到监听控制台关闭方法。

这么简单的代码,我就不写成插件装逼了,需要的时候直接用即可。在 runjs 上写了个 demo,打开预览下效果吧!

预览: http://sandbox.runjs.cn/show/vjtgjbzg

后序

控制台环境下有很多功能都很方便很好用,多读读会发现很多神奇的技巧。

本文同步至我的个人博客:http://www.52cik.com/2016/04/27/chrome-console-open.html

Chrome 监听 console 打开的更多相关文章

  1. javascript 反调试 监听用户打开了Chrome devtool

    let div = document.createElement('div'); let loop = setInterval(() => {     console.log(div);     ...

  2. [Android Pro] 监听WIFI 打开广播

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-perm ...

  3. android监听屏幕打开关闭广播无响应的情况

    android在屏幕打开和关闭的时候会发出广播,但是如果receiver配置在AndroidManifest.xml中时,receiver是接受不到任何广播的. <receiver androi ...

  4. 如何实现监听 console.log

    var lastLog; console.oldLog = console.log; console.log = function(str) { console.oldLog(str); lastLo ...

  5. chrome 监听touch类事件报错:无法被动侦听事件preventDefault

    先上错误信息: Unable to preventDefault inside passive event listener due to target being treated as passiv ...

  6. [Android Pro] 监听Blutooth打开广播

    <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission a ...

  7. Android onclick监听事件打开新界面

    一.新建工程 二.新建XML代码 新建一个Button <Button android:layout_width="wrap_content" android:layout_ ...

  8. oracle 监听服务OracleOraDb11g_home1TNSListener打开后立马停止错误

    首先我真得吐槽一下,我安装这个破软件感觉真的是把能遇到的错误都遇到一遍了,生气!!!!!!! 关于监听服务OracleOraDb11g_home1TNSListener打开后立马停止这个错误,我的解决 ...

  9. 连接linux数据库Oracle时报错ORA-12541: TNS: 无监听程序

    远程服务器的数据库服务未开启,以及监听未打开 连接oracle 启动服务,startup 切换到oracle /bin 目录,cd $ORACLE_HOME/bin 启动监听, lsnrctl sta ...

随机推荐

  1. Sql Server之旅——第八站 复合索引和include索引到底有多大区别?

    周末终于搬进出租房了,装了宽带....才发现没网的日子...那是一个怎样的与世隔绝呀...再也受不了那样的日子了....好了,既然网 安上去了,还得继续我的这个系列. 索引和锁,这两个主题对我们开发工 ...

  2. 0001 Oracle数据库安装

    从这个月初开始学习Oracle,因为完全是零起步,就从Oracle的下载安装开始一点一点学起,今天把系统重新做了,就再安装了一遍Oracle11gR2,把安装过程记录一下: 一.安装Oracle数据库 ...

  3. 学习myBatis - 如何配置myBatis

    这篇文章主要学习如何配置myBatis. 要学习新东西要讲究方法,要从三个层面去理解它:它是什么(what),为什么要学它(why),怎么用它(how).有了学习方法学习的效率才高. 1.myBati ...

  4. Java api 入门教程 之 JAVA的String 类

    1.String对象的初始化 由于String对象特别常用,所以在对String对象进行初始化时,Java提供了一种简化的特殊语法,格式如下: String s = “abc”; s = “Java语 ...

  5. 烂泥:ubuntu下配置msmtp+mutt发送邮件

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb. 本文主要介绍如何在Linux下使用msmtp+mutt发送邮件,当然Linux下发送邮 ...

  6. 高性能MySQL笔记 第6章 查询性能优化

    6.1 为什么查询速度会慢   查询的生命周期大致可按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中“执行”可以认为是整个生命周期中最重要的阶段. ...

  7. x01.Lab.OpenCV: 计算机视觉

    横看成岭侧成峰,计算视觉大不同.观看的角度不同,成像自然不同,这对计算机视觉来说,是个大麻烦.但计算机视觉应用如此广泛,却又有不得不研究的理由.指纹机大家都用过吧,这不过是冰山之一角.产品检测,机器人 ...

  8. shell脚本实现随机筛选

    #!/bin/bash name=(val1 val2 val3 val4 ...) a=$() #以时间产生随机数向39取余得到0~38的值

  9. android ListView 和 BaseAdapter 应用

    步聚: 1.建立ListView对象:--(作用:绑定Adapter呈现数据) 2.建立ListView实现的Item栏位.xml布局:--(作用:实现ListView的栏位布局) 3.建立Item. ...

  10. python enumerate函数用法

    enumerate函数用于遍历序列中的元素以及它们的下标 i = 0 seq = ['one', 'two', 'three'] for element in seq: print i, seq[i] ...