为什么 console.log 直接打印的对象和打印 JSON.stringify 后的对象会有差异?

155 天前
 WangLiCha

开发用到了 AntV G6 ,然后发现有一个对象的字段怎么都获取不到,但是直接打印对象又能看到这个字段。具体来说是这样:

我想通过一个内置的方法来设置边的属性,需要拿到 edge 对象的 targetNode 字段。直接用 console.log 打印 edge 方法是能看到确实有一个 targetNode 字段的,但是实际运行的时候 edge.targetNode 的值一直是 undefined 。接下来我就发现直接打印 edge 输出的结果和打印 JSON.stringify(edge)看到的结果是不一样的,前者会多出好几个字段。

这是个什么原理?为什么会有这种状况出现?这种条件下我怎么才能获取到我想要的 targetNode 字段呢?

1649 次点击
所在节点    程序员
14 条回复
whatFoxSay
155 天前
有没有可能你操作完之后这个 targetNode 被改成 undefined 得了,stringfy 的时候只是字符串不会和原来对象有引用关系
WangLiCha
155 天前
@whatFoxSay 没有操作过啊,我对 edge 对象的所有操作就是这一行打印了。另外 log 打印出来的对象会被引用影响的话不会干扰开发调试吗?
flyqie
155 天前
JSON.stringify 跟 console.log 的结果一定会有差异,JSON.stringify 只会处理标准值,但 js 里面的黑魔法太多,所以你最好还是看下那些字段是怎么加上的。。
codehz
155 天前
祖传问题了,devtools 点开直接打印的对象的时候会当场求值,如果那时候引用被改了就凉了,我记得 chrome 甚至会给一个警告
flyqie
155 天前
@flyqie #3

其实也不能算黑魔法。。叫习惯了。。
cxe2v
155 天前
直接 console.log 输出是这个对象的引用,内部的字段在 console 的时候不一定有最后你展开时候查看到的值

JSON.stringify 是把对象字符串化,得到的结果就固定在 stringify 这个时刻

你这个情况的原因是因为 targetNode 这个字段是在你 console 之后才被添加到 edge 对象里的

解决方法,尝试通过 nextTick 或者 setTimeout 延迟获取 targetNode
liuhuihao
155 天前
原因是 devtools console.log 的时候有些时候是你点击展开的时候才去获取这个值而不是打印的时候的值。
至于 console.log 和 JSON.stringify 不一样的原因那就他太多了,toJSON 方法、undefined 、非可枚举一类的都不会出现在 JSON.stringify 里,但你发的这个问题应该不是这个导致的。单纯是你打印的时候本身就是 undefined ,然后在你展开属性的时候获取的是改后的值
liuhuihao
155 天前
@liuhuihao

const a = {a:{}}
console.log(a,JSON.stringify(a))
a.targetNode=123

简单的代码可以试一下
console.log 打印的是对象的引用,你后给这个对象加上属性也会出现在 log 里
liuhuihao
155 天前
@WangLiCha 你 打印 的时候这个对象里其实还没有 targetNode 字段,这也就是为啥 JSON.stringify 里没有,这个 targetNode 字段是在你 console.log 代码执行之后、点击 devtools 对象的展开之前 才被添加到对象上的。
guorenjie
155 天前
wangtian2020
155 天前
打印的是对象引用,要么加上 debugger 暂停下面的代码,要么完全拷贝一份对象并且保证切断对象间的数据引用
NerbraskaGuy
155 天前
用 proxy 做数据监听吧,json stringfy 会因为各种限制导致数据丢失
shanhaisilu
155 天前
let obj = {a:1};
console.log(obj);
obj.b = 2

运行一下这三句代码,看看控制台输出的对象,再把对象展开看看,就很明确了。控制台直接输出的时候,输出的引用地址的引用,展开之后能看到的是引用地址内的内容,而这个内容是可以在输出之后被修改的
minglanyu
155 天前
console.log 的时候 targetNode 还没有被添加到 edge 上。
因为 JOSN.stringify()打印的是对象的快照而不是引用,所以 JOSN.stringify()时没有打印出结果。
但是因为 console.log 打印的是引用,所以也会打印出 TargetNode 。

可以试下用 Proxy 劫持下 edge ,当 targetNode 被添加时,打印对象。

把下面例子里的 targetObject 换成 edge 试下。

```
const targetObject = {};

const proxy = new Proxy(targetObject, {
defineProperty(target, property, descriptor) {
console.log(`试图向属性 ${property} 添加值`);

// 允许正常添加名为 "targetNode" 的属性
const result = Reflect.defineProperty(target, property, descriptor);

// 打印被劫持对象的值和修改后的对象
console.log("被劫持对象的值:", targetObject);
console.log("修改后的对象:", proxy);

return result;
}
});

// 通过代理添加属性
proxy.targetNode = "some value"; // 试图向属性 targetNode 添加值
// 输出: 被劫持对象的值: { targetNode: 'some value' }
// 输出: 修改后的对象: { targetNode: 'some value' }
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/998689

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX