Daily-Question icon indicating copy to clipboard operation
Daily-Question copied to clipboard

【Q665】JS 如何检测到对象中有循环引用

Open shfshanyue opened this issue 3 years ago • 9 comments

示例,如下数据为循环结构/循环引用

const user = { id: 10086, name: '山月' }
user._user = user

追问:

  1. 由于 JSON.stringify 序列化对象时,将跳过不枚举的 key,因此此时可不考虑不可枚举的 key
  2. 如果考虑不可枚举 key 与 Symbol 如何处理

shfshanyue avatar Jul 22 '21 10:07 shfshanyue

TODO

shfshanyue avatar Jul 22 '21 10:07 shfshanyue

const a = {
a:1,
c: 3
}

const b = {
  a: a,
  c: 3
}
a.b = b;

//JSON.stringify(a);

const keyMap = new Map();
keyMap.set(a, "1");
keyMap.set(b, "2");
function circle(target) {
  const keys = Object.keys(target);
  for(let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const val = target[key];
    if(keyMap.has(val)) {
      return true
    }else {
      keyMap.set(val, key)
      if(typeof val === 'object') {
        circle(val)
      }
    }
  }
  return false;
}
console.log(circle(a))

yoyou avatar Jul 22 '21 11:07 yoyou

const a = {
a:1,
c: 3
}

const b = {
  a: a,
  c: 3
}
a.b = b;

//JSON.stringify(a);

const keyMap = new Map();
keyMap.set(a, "1");
keyMap.set(b, "2");
function circle(target) {
  const keys = Object.keys(target);
  for(let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const val = target[key];
    if(keyMap.has(val)) {
      return true
    }else {
      keyMap.set(val, key)
      if(typeof val === 'object') {
        circle(val)
      }
    }
  }
  return false;
}
console.log(circle(a))

可以将 Object.keys() 替换为 Reflect.ownKeys()

iotale avatar Jul 22 '21 11:07 iotale

function isCircularReference(value) {
  const isObject = value => Object.prototype.toString.call(value) === '[object Object]';
  const memory = new WeakMap();
  let isCycled = false;
  const traverse = function(value) {
    if (isObject(value)) {
      if (memory.has(value)) {
        isCycled = true;
        return;
      }
      memory.set(value, true);
      const keys = Object.keys(value);
      for (const key of keys) {
        traverse(value[key]);
      }
    }
  }
  traverse(value);
  return isCycled;
}

haotie1990 avatar Jul 22 '21 13:07 haotie1990

function isCircularReference(value) {
  const isObject = value => Object.prototype.toString.call(value) === '[object Object]';
  const memory = new WeakMap();
  let isCycled = false;
  const traverse = function(value) {
    if (isObject(value)) {
      if (memory.has(value)) {
        isCycled = true;
        return;
      }
      memory.set(value, true);
      const keys = Object.keys(value);
      for (const key of keys) {
        traverse(value[key]);
      }
    }
  }
  traverse(value);
  return isCycled;
}
// isObject改为isPrimitive
const isPrimitive = value => /Number|Boolean|String|Undefined|Null|Symbol/.test(Object.prototype.toString.call(value));

haotie1990 avatar Jul 22 '21 14:07 haotie1990

希望不可枚举和Symbol 可以Reflect.ownKeys(obj).map(curr => obj[curr]) 获取全部的key对应的values Object上面也有 不过是分开的 两个API

function checkObj (obj, set = new Set()) {
    if (typeof obj === 'object' && obj !== null || Array.isArray(obj)) {
        if (set.has(obj)) {
            return true
        } else {
            set.add(obj)
        }
        return Object.values(obj).some(curr => {       
            return checkObj(curr, set)
        })
    }
    return false
}

heretic-G avatar Jul 24 '21 08:07 heretic-G

function isCircular(obj) {
    try {
      JSON.stringify(obj) 
    } catch(e) {
       return e.message.includes('Converting circular structure to JSON');
    }
    return false;
}

Hishengs avatar Aug 30 '21 11:08 Hishengs

上面没有一个答案是对的啊,试试这个对象返回的都是true

const c = {}; const d = { e:c, f:c }

cloudGrin avatar Nov 09 '23 06:11 cloudGrin

function hasCircularReference(obj, seenObjects = new Set()) {
  if (typeof obj !== 'object' || obj === null) {
    return false;
  }

  if (seenObjects.has(obj)) {
    return true;
  }

  seenObjects.add(obj);

  for (let key in obj) {
    if (hasCircularReference(obj[key], new Set([...seenObjects]))) {
      return true;
    }
  }

  return false;
}

cloudGrin avatar Nov 09 '23 06:11 cloudGrin