我是靠谱客的博主 花痴白云,最近开发中收集的这篇文章主要介绍 一个“诡异”的console.log()结果,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一个诡异的结果

在前端开发中,我们都少不了用console.log来输出变量和调试。可是在使用它的过程中,偶尔也会出现一些让我们很费解的行为,如下图:

图片描述

是不是很诡异:)

这个诡异的行为是怎么来的呢?其实怪我“断章取义”了。控制台上我执行的代码其实是:

图片描述

注意到展开的数组旁边有一个小i,将鼠标移动上去,会出现提示文字:

Value below was evaluated just now.

简单翻译一下就是:下面展示的值,是刚刚解释执行(evaluated,或者你可以用你熟悉的eval函数来理解这个单词)的结果。

这句话该怎么理解呢?注意到:小i这个提示仅在我们展开数组的时候才会出现,而展开前控制台上展示的确实是一个空数组[]。因此我们可以将展开前后认为是这个值的两个状态。

现在,我们定位到了这个诡异的行为是和展开相关的,那么让我们来实验一下展开这个操作会对log出来的值产生什么影响呢?我们将一行一行地在控制台执行下面三行js代码:

var a = []
console.log(a)
a.push(1, 2, 3, 4, 5)

在执行a.push(1)之前展开[],会得到下面的结果,应该算是一个预期结果:

图片描述

而在执行a.push(1)之后再展开[],就会得到一开始我给大家看的“诡异”结果了。

图片描述

现在回过头来看 Value below was evaluated just now. 这句话,其实说的就是,展开后的值,其实是在你点击展开小三角的时候,才 “eval” 出来的。

再看下面一个例子:

图片描述

图中的结果,我是在执行了a = [1, 2, 3, 4, 5]这句话之后才点击的小三角,然而结果却没有变成“诡异”结果的样子。这是因为后面我更新数组是直接采用变量赋值的方法,相当于修改了变量a的引用,就和变量的引用赋值一样,是影响不了a之前所引用的数组的。

也就是说,console.log()在展开时用于eval的,是变量指向的引用而不是变量本身。

试试其他浏览器

console.log的这个行为并不是chrome限定,在Firefox和Safari中你都能得到同样的行为。

Firefox:

图片描述

Safari中由于console.log展不开,因此使用console.dir来展开:

图片描述

Edge下就不是这样子了233:

图片描述

所以如果你不想要这个“诡异”的结果的话,可以用 Edge 调试哦:)

如果不用Edge呢?

一个正常的思路是,如果能够让console.log直接输出就是展开的,那么这个行为就不会诡异了。

不过很不幸,我没有找到能够做这件事情的API。不过,我们可以借助console.group这个方法,自己造一个展开的结构出来。

/**
* expandLog
*
* @desc 自动展开的 console.log,实现参考:
* https://stackoverflow.com/questions/10464844/is-there-a-way-to-auto-expand-objects-in-chrome-dev-tools#27610197
* @author leuisken <leuisken@foxmail.com>
* @param {Object} obj 需要 log 的对象
*/
function expandLog(obj) {
if (Array.isArray(obj)) {
obj.forEach((value, index) => {
console.group(`${index} : ${type(value)}`);
expandLog(value);
console.groupEnd();
});
}
else if (isPlainObject(obj)) {
Object.keys(obj)
.forEach(key => {
const value = obj[key];
console.group(`${key} : ${type(value)}`);
expandLog(value);
console.groupEnd();
});
}
else {
console.log(obj);
}
return;
/**
* type
*
* @desc 针对部分常见类型给予更好的输出方式
* @param {Object} obj 传入的对象
* @return {string} 类型字符串
*/
function type(obj) {
const typeofResult = typeof obj;
if (typeofResult !== 'object') {
return typeofResult;
}
else if (obj === null) {
return 'null';
}
else if (Array.isArray(obj)) {
return 'Array';
}
else if (obj instanceof RegExp) {
return 'RegExp';
}
else if (obj instanceof Date) {
return 'Date';
}
return 'Object';
}
/**
* isPlainObject
*
* @desc 即:jQuery.isPlainObject
* @param {Object} obj 传入的对象
* @return {boolean} 是否为 PlainObject
*/
function isPlainObject(obj) {
if (!obj
|| obj.toString() !== '[object Object]'
|| obj.nodeType
|| obj.setInterval
) {
return false;
}
if (obj.constructor
&& !obj.hasOwnProperty('constructor')
&& !obj.constructor.prototype.hasOwnProperty('isPrototypeOf')
) {
return false;
}
let key;
for (key in obj) {}
return key === undefined || obj.hasOwnProperty(key);
}
}

这里写这个方法只是示个意,估计一般也不会有谁这么做。。其实很无奈,就和console.logconsole.dir没有提供默认展开的API一样,console.group也没有提供默认收起的API。。。。

题外话

在搜索能否默认展开console.log结果的时候,在Stack Overflow上无意间搜到了这样一个结果。

https://stackoverflow.com/que...

原来 chrome 的 console,也有自己的 console 啊。。

最后

以上就是花痴白云为你收集整理的 一个“诡异”的console.log()结果的全部内容,希望文章能够帮你解决 一个“诡异”的console.log()结果所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部