Skip to content

利用toString检测浏览器devTool是否为开启状态 #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
haoliangwu opened this issue May 10, 2018 · 7 comments
Open

利用toString检测浏览器devTool是否为开启状态 #32

haoliangwu opened this issue May 10, 2018 · 7 comments

Comments

@haoliangwu
Copy link

haoliangwu commented May 10, 2018

f = function(){}
f.toString = function () {
    // do something when devTool is opened
}
console.log('%c', f);

关于检测 devTool 是否为打开状态当前已经有好多方案了,比如轮询检测 window 的内外宽高差、对 html 元素注册 id 的 getter 等,但是这些方法要不具有侵入性,要不无法满足 devTool 是悬浮状态的情况,上面的方法可能更好一下,亲测 chrome 和 ff 没问题。

@Tao-Quixote
Copy link

Tao-Quixote commented May 10, 2018

可以介绍一下 console.log('%c', f); 为什么会在 devTools 打开时执行吗?

刚才试了一下,并不是每次打开 devTools 都会执行一次 console.log(),例如:

console.log(Date.now())

每次打开 devTools 时输出的都是同样的值,并没有每次都重新执行 Date.now()

@haoliangwu
Copy link
Author

haoliangwu commented May 10, 2018

@Tao-Quixote console.log('%c', f);这个不是重点,主要是为了使打印出的文字变成透明,重点是f = function(){},因为 devTool 在打印函数对象时会调用它们的 toString 方法,这里如果换成 f={} 就不可以了,大概是这样。

@Tao-Quixote
Copy link

@haoliangwu

你上面说的这个原理我明白;

我不明白的是:为什么在打开 devTools 时会再次执行 console.log('%c', f);,而 console.log(Date.now()) 这个就算是多次重复打开 devTools 也不会多次执行。而且我试了一下,不只是 console.log('%c', )console.log('%d', )console.log('%f', )console.log('%s', )这些,都会在打开 devTools 时再次执行;而不包括 string substitutions 的 console.log() 就不会重复执行,即使写的是函数调用,如 console.log(Date.now()) 这种也不会重复执行 Date.now(),每次输出的时间戳都是同一个。

@haoliangwu
Copy link
Author

@Tao-Quixote 没啊,我这里包不包含string substitutions都会重复执行啊,录一个gif:
record

@Tao-Quixote
Copy link

@haoliangwu
Mmmm....
想了一下,应该是这么个情况:
JavaScript 中函数的参数传递的应该是值:

// 传递的是 foo 的地址,在输出到控制台时进行隐式类型转换
// 由于转换目标类型为 string,所以调用 toString 方法
function foo () {}
foo.toString= function () {
  // 打开 devTools 时的逻辑
  ...
}
console.log(foo);

而不能通过下面这种方式来实现:

function foo () {
  // 打开 devTools 时的逻辑
  ...
}
console.log(foo())

上面的方式会将 foo() 的结果直接作为参数传递,所以 foo 只会调用一次,从而不能实现每次打开 devTools 时执行特定逻辑的功能。

所以,你实验的时候每次都会输出不同的值,而我通过 console.log(Date.now()) 时每次都输出同样的值。因为 Date.now() 只执行了一次。

不知道这样理解对不对?请大佬指点。

@haoliangwu
Copy link
Author

@Tao-Quixote 嗯,好像是这么一回事,你可以试试@迷渡大佬现身说法一下,哈哈

@justjavac
Copy link
Owner

justjavac commented May 10, 2018

正则,函数,日期都可以,因为控制台会隐式调用这几个 ObjecttoString 方法。

子类同样适用:

class MyDate extends Date {};

var f = new MyDate();

f.toString = function () {
    console.log(performance.now());
    return performance.now();
}

console.log('%s', f);

而对于 Object,只会调用默认的 toString 方法,永远不会调用自定义的:

var f = {};
console.log('%s', f);

输出 Object

var f = {};

f.toString = function () {
    console.log(performance.now());
    return 'foo';
}

console.log('%s', f);

依然输出 Object

如果想输出 foo,则需要:

var f = {};

f.toString = function () {
    console.log(performance.now());
    return 'foo';
}

console.log('%s', f + '');
                 //  |
                 //  |
                 // 这里

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants