map console.log 偶遇输出问题如下

234 阅读3分钟

1.场景,

最近在做微信小程序,在处理一段函数时,发现在函数头部输出的console.log()居然输出了函数中后续处理的函数值,(手动狗头🤣,js同步无了)

2.问题再现

function a(){
    let obj = [{}]
    console.log(obj)
    obj.map(item => {
        item.a = '1'
    })
    console.log(obj)
}
a()

其输出如下,(大家可以贴入浏览器-控制台验证)

捕获.JPG

此时可以清晰的发现,发现函数的第一个console.log()和函数的第二个console.log()居然输出的是同一个值,😫第一个输出居然不是‘[{}]’,这怎么办呀,难不成和js编译有关?变量提升,赋值?亦或是函数内部的奇怪编译顺序?

震惊啊😃\color{red}{**震惊啊😃**},于是乎,个人进行了js编译的相关编译过程的复习,过程中却并没有找出相关问题,发现这和常见的编译过程并没有太大关系

后续经过了解,在《JavaScript异步编程》书中解释如下:

WebKit的console.log并没有立即拍摄对象快照,相反,它只存储了一个指向对象的引用,然后在代码返回事件队列时才去拍摄快照。
Node的console.log是另一回事,它是严格同步的,因此同样的代码输出却为{}

并没有什么规范或一组需求指定console.* 方法族如何工作——它们并不是JavaScript 正式的一部分,而是由宿主环境(请参考本书的“类型和语法”部分)添加到JavaScript 中的。因此,不同的浏览器和JavaScript 环境可以按照自己的意愿来实现,有时候这会引起混淆。 尤其要提出的是,在某些条件下,某些浏览器的console.log(..) 并不会把传入的内容立即输出。出现这种情况的主要原因是,在许多程序(不只是JavaScript)中,I/O 是非常低速的阻塞部分。所以,(从页面/UI 的角度来说)浏览器在后台异步处理控制台I/O 能够提高性能,这时用户甚至可能根本意识不到其发生。

书中建议:

如果遇到这种少见的情况,最好的选择是在JavaScript 调试器中使用断点,而不要依赖控制台输出。次优的方案是把对象序列化到一个字符串中,以强制执行一次“快照”,比如通过JSON.stringify(..)。

此时,按照书中的JSON.stringify(obj)进行输出

function a(){
    let obj = [{}]
    console.log(JSON.stringify(obj))
    obj.map(item => {
        item.a = '1'
    })
    console.log(obj)
}
a()

捕获.JPG

推论:JSON.stringify(obj)得出的值为[{}]为原猜想值,后续改变是由于,个人点击控制台对象进行展开,浏览器对于该值有一次进行求值,此时内存中数据已被后续改变,故而表现为异步输出。

得出如下结论,

  1. 在WebKit运行环境下,对引用型数据建议不要使用console.log()进行调试,浏览器会表现为异步输出
  2. 基本数据类型不存在该问题,
  3. node环境中该问题不存在

3.原场景

为接近原场景,所以贴出测试数据,以及修改代码如下,

let arr  ={
company_name: "parent",
company_no: 'demo123',
id_company: "787893298900demo999",
                    children : [
                    {
                        id_company: '999感冒灵',
                        branch_id: 'aaaa',
                        id_store: '0789423785345一83475一34与',
                        shop_name: '蓝湖大街'
                    },
                    {
                        id_company: '777感冒灵',
                        branch_id: 'bbbb',
                        id_store: '365gfggggggggggg',
                        shop_name: '哈兰大姐'
                    }
                ]}
let aaa = []
aaa.push(arr)
function handler(item) {
    console.log(item)
    item.forEach((item) => {
                item.children.map((item1, index) => {
                    if (!item1.isChecked) {
                        item.children = item.children.splice(index, 1);
                    }
                });
            });
    console.log(item)
}
handler(aaa)

image.png