当前位置:首页 > Web开发 > 正文

(当然不止这一种情况

2024-03-31 Web开发

本文主要从 JS 中为什么会呈现循环引用,垃圾回收计谋中引用计数为什么有很大的问题,以及循环引用时的东西在使用 JSON.stringify 时为什么会报错,怎样解决这个问题简单谈谈本身的一些理解。

1. 什么是循环引用

当东西 1 中的某个属性指向东西 2,东西 2 中的某个属性指向东西 1 就会呈现循环引用,(固然不止这一种情况,不过道理是一样的)下面通过代码和内存示意图来说明一下。

function circularReference() { let obj1 = { }; let obj2 = { b: obj1 }; obj1.a = obj2; }

上述代码在内存中的示意图

技术图片

从上图可以看出 obj1 中的 a 属性引用 obj2,obj2 中的 b 属性引用 obj1,这样就组成了循环引用。

2.JS 中引用计数垃圾回收计谋的问题

先简单讲一下 JS 中引用垃圾回收计谋梗概是什么样的一个道理,当一个变量被赋予一个引用类型的值时,,这个引用类型的值的引用计数加 1。就像是代码中的 obj1 这个变量被赋予了 obj1 这个东西的地点,obj1 这个变量就指向了这个 obj1(右上)这个东西,obj1(右上)的引用计数就会加1.当变量 obj1的值不再是 obj1(右上)这个东西的地点时,obj1(右上)这个东西的引用计数就会减1.当这个 obj1(右上)东西的引用计数酿成 0 后,垃圾收集器就会将其回收,因为此时没有变量指向你,也就没步伐使用你了。

看似很合理的垃圾回收计谋为什么会有问题呢?

就是上面讲到的循环引用导致的,下面来分析一下。当 obj1 这个变量执行 obj1 这个东西时,obj1 这个东西的引用计数会加 1,此时引用计数值为 1,接下来 obj2 的 b 属性又指向了 obj1 这个东西,所以此时 obj1 这个东西的引用计数为 2。同理 obj2 这个东西的引用计数也为2.

今世码执行完后,会将变量 obj1 和 obj2 赋值为 null,但是此时 obj1 和 obj2 这两个东西的引用计数都为1,并不为 0,所以并不会进行垃圾回收,但是这两个东西已经没有感化了,在函数外部也不成能使用到它们,所以这就造成了内存泄露。

在此刻广泛给与的符号断根回收计谋中就不会呈现上面的问题,符号断根回收计谋的大抵流程是这样的,最开始的时候将所有的变量加上符号,当执行 cycularReference 函数的时候会将函数内部的变量这些符号断根,在函数执行完后再加上符号。这些被断根符号又被加上符号的变量就被视为将要删除的变量,原因是这些函数中的变量已经无法被访谒到了。像上述代码中的 obj1 和 obj2 这两个变量在刚开始时有符号,进入函数后被断根符号,然后函数执行完后又被加上符号被视为将要断根的变量,因此不会呈现引用计数中呈现的问题,因为符号断根并不会关心引用的次数是几多。

3. 循环引用的东西使用 JSON.stringify 为什么会报错

JSON.stringify 用于将一个 JS 东西序列化为一个 JSON 字符串,假设此刻我们要将 obj1 这个东西序列化为 JSON 字符串,此刻我们先将 obj1 这个东西打印出来看一下。

function circularReference() { let obj1 = { }; let obj2 = { b: obj1 }; obj1.a = obj2; console.log(obj1); } circularReference();

功效如下所示:

技术图片

obj1 这个东西和 obj2 会无限彼此引用,JSON.tostringify 无法将一个无限引用的东西序列化为 JOSN 字符串。

下面是 MDN 的解释:

JSON.stringify() 将值转换为相应的JSON格局:

转换值如果有 toJSON() 要领,该要领界说什么值将被序列化。

非数组东西的属性不能保证以特定的挨次呈此刻序列化后的字符串中。

布尔值、数字、字符串的包装东西在序列化过程中会自动转换成对应的原始值。

undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(呈此刻非数组东西的属性值中时)或者被转换成 null(呈此刻数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined).

对包罗循环引用的东西(东西之间彼此引用,形成无限循环)执行此要领,会抛堕落误。

所有以 symbol 为属性键的属性城市被完全忽略失,即便 replacer 参数中强制指定包罗了它们。

Date 日期挪用了 toJSON() 将其转换为了 string 字符串(同Date.toISOString()),因此会被当做字符串措置惩罚惩罚。

NaN 和 Infinity 格局的数值及 null 城市被当做 null。

其他类型的东西,包孕 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。

我们可以从加粗的字体中看到,对包罗循环引用的东西执行 JSON.stringify,会抛堕落误。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/31950.html