报错:

[Vue warn]: Error in nextTick: "TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Vue'
    |     property '$options' -> object with constructor 'Object'
    |     property 'router' -> object with constructor 'VueRouter'
    --- property 'app' closes the circle"

解析:

一般报错TypeError: Converting circular structure to JSON是因为存在循环引用,并且使用JSON.stringify方法去转化成字符串。下面举一个简单地例子:

  • 报错代码

    const x = { a: 8 };
    const b = { x };
    b.y = b; // 循环引用
    JSON.stringify(b); // 触发报错
    
  • 解决

    const x = { a: 8 };
    const b = { x };
    b.y = JSON.parse(JSON.stringify(b)); // 隐式深拷贝,主要实现深拷贝,解除循环引用
    JSON.stringify(b);
    

    也可以不使用深拷贝,直接去掉循环引用的代码,问题的关键点是解除循环引用

  • 本博文报错位置不能显式看到循环引用,因为循环引用的代码不是自己写的,而是框架代码自己实现的,因此发现问题的产生地方更难一点。经过大约一下午时间头都快爆炸了,终于看到了黎明曙光。发现产生问题的原因:

    • vuex中的状态管理state中存储了router实例(组件中获取的this.$route),存在循环引用
    • vuex使用了插件vuex-persistedstate

    state中有了循环引用,插件vuex-persistedstate要执行JSON.stringifystate数据转化成字符串然后存储到浏览器本地存储。

    接下来就是解决,那就是解除循环引用,解除办法就是对组件中获取的this.$route进行深拷贝,然后再存储到state

    /**
     * 获取数据类型
     * @param {All} [o] 需要检测的数据
     * @returns {String}
     */
    export function getType(o){
      return Object.prototype.toString.call(o).slice(8,-1);
    }
    
    /**
     * 判断是否是指定数据类型
     * @param {All} [o] 需要检测的数据
     * @param {String} [type] 数据类型
     * @returns {Boolean}
     */
    export function isKeyType(o, type) {
    	return getType(o).toLowerCase() === type.toLowerCase();
    }
    
    /**
     * 深拷贝,支持常见类型 object Date Array等引用类型
     * @param {Any} sth
     * @return {Any}
     */
    export function deepClone(sth) {
      let copy;
      if (null == sth || "object" != typeof sth) return sth;
      if (isKeyType(sth, 'date')) {
        copy = new Date();
        copy.setTime(sth.getTime());
        return copy;
      }
      if (isKeyType(sth, 'array')) {
        copy = [];
        for (let i = 0, len = sth.length; i < len; i++) {
          copy[i] = deepClone(sth[i]);
        }
        return copy;
      }
      if (isKeyType(sth, 'object')) {
        copy = {};
        for (let attr in sth) {
          if (sth.hasOwnProperty(attr)) copy[attr] = deepClone(sth[attr]);
        }
        return copy;
      }
      return null;
    }
    

    深拷贝源码此项目包含很多前端通用方法。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐