console的知识点避坑

console的知识点

问题起因:

前几日同事对树形数据进行处理,发现代码可以按照逻辑运行,但是console获取到的后端数据里,没有被处理的树形数据.

这里简单复现一下问题代码:

let res = await getTreeMenuList()
console.log(res)
const { menuList } = res.data
generatorRoutes(menuList: any) {
        let routes: any = [] 
        const deepList = (list: any) => {   
            while (list.length) {
                let item = list.pop()
                if (item.children && !item.action) { 
                    deepList(item.children)
                }
            }
        }
        deepList(menuList) 
        return routes
    }
generatorRoutes(menuList)

以上的代码在两次console的地方都是显示有东西,但是实际点开的时候,menuList的length为0

如果你只想知道简单原因和解决方法:

因为函数处理的逻辑里给list.pop(),且没有深拷贝切断联系.

因为对象是引用类型,所以此时的操作改变了.menuList,

所以会发现,控制台打印的时候显示的是有数组内容,但是点开会发现length:0,且没有内容.

所以可知:切断联系或者不修改堆内存就好了.(深拷贝或者不对数组进行pop()之类的改变操作即可)

问题解析:

上面已经简单说明了问题出现的原因,接下来稍微深入一点.

因为操作的还是同一个堆内存,所以控制台点开,打印的是处理之后数据内容,因为递归pop()了所以length是0

那么,为什么呢?

很简单,其实console.log()在控制台输出引用值时确实是当时的值,但是你点开箭头的时候它会重新获取这些引用的值

这里写一个简单的示例代码:

let test = {a:{b:1}}
console.log(test.a)
test.a.b = 2

以上代码会出现的效果就是:
在这里插入图片描述

显示的是{b:1},但是点开是b:2.

这就是因为在console.log的时候快照拍到的是{b:1}栈内存,但是因为下面的代码修改了堆内存,所以重新获取引用的值:{b:2}

当然,我也看到有人说是因为console异步操作,因为:

  let test = { a: { b: 1 } }
  Promise.resolve().then(() => { console.log(test.a) })
  setTimeout(() => { console.log(test.a) }, 0)
  test.a.b = 2

console的知识点避坑_第1张图片

不管是宏任务还是微任务打印的出来的结果点开和直接看到的都是{b:2}.

但是!这实际上是因为同步代码执行完了才执行的微任务,然后宏任务,所以此时此刻的test.a不管是当时的值还是重新获取的引用值其实都是{b:2};了.这和同步异步是没有关系的.

扩展

  let test = { a: { b: 1 } }
  console.log(test.a)
  test.a = { b: 2 }

在这里插入图片描述

以上的代码会出现不管是当时,还是重新获取都是{b:1}, 原因其实很简单,因为 {b: 2} 是复杂类型,堆内存,a的堆内存都换了,所以按照console时的栈内存指向,其实还是{b:1}所在的堆内存,而不是新的堆内存{b:2}

 let test = { a: { b: 1 } }
  console.log(test.a.b)
  test.a.b = 2

在这里插入图片描述

以上代码直接打印1,不会改变,因为,test.a.b就是栈内存,没有指向的堆内存.他就是简单类型.也不需要重新获取引用的值…

解决方法:

深拷贝切断引用,不修改原对象都可.

如果不影响代码的逻辑当然也可以不改.(其实断点的时候也是可以看到正确的打印.)

你可能感兴趣的:(javascript,前端,vue.js)