JS怎樣判斷一個對象是否存在"環(huán)"?

前段時間,在做阿里前端筆試題的時候,遇到了這樣一道編程題,題目內(nèi)容如下:

JSON.stringify 的功能是,將一個 JavaScript 字面量對象轉(zhuǎn)化為一個 JSON 格式的字符串。例如

const obj = {a:1, b:2}
JSON.stringify(obj) // => '{"a":1,"b":2}'

當要轉(zhuǎn)化的對象有“環(huán)”存在時(子節(jié)點屬性賦值了父節(jié)點的引用),為了避免死循環(huán),JSON.stringify 會拋出異常,例如:

const obj = {
  foo: {
    name: 'foo',
    bar: {
      name: 'bar'
      baz: {
        name: 'baz',
        aChild: null  //待會讓它指向obj.foo
      }
    }
  }
}
obj.foo.bar.baz.aChild = obj.foo // foo->bar->baz->aChild->foo 形成環(huán)
JSON.stringify(obj) // => TypeError: Converting circular structure to JSON

請完善以下“環(huán)”檢查器函數(shù) cycleDetector,當入?yún)ο笾杏协h(huán)時返回 true,否則返回 false。

function cycleDetector(obj) {   
  // 請?zhí)砑哟a
}

“環(huán)”的形成是因為對象的子節(jié)點屬性賦值了父節(jié)點的引用,所以我們需要記錄下父節(jié)點的地址,然后再拿其子節(jié)點的屬性與之前記錄下的父節(jié)點地址做一個比較,當結(jié)果一致時,就形成了“環(huán)”。

那么,在“環(huán)”檢測器函數(shù)中,我們首先需要遍歷這個對象的屬性,前面提到了引用,那么我們只需對Object類型的屬性進行處理即可(簡單數(shù)據(jù)類型不存在引用關(guān)系)。對于Objcet類型的屬性,我們先與記錄下來的父節(jié)點地址做一個對比,如無匹配項,將當前屬性地址記錄下來,然后遍歷其子節(jié)點屬性,一層一層找下去。下面開始上代碼:


function cycleDetector(obj) {

    var hasCircle = false,            //  定義一個變量,標志是否有環(huán)
        cache = [];                   //  定義一個數(shù)組,來保存對象類型的屬性值

    (function(obj) {
        var keys = Object.keys(obj);              //獲取當前對象的屬性數(shù)組
        for (var i = 0; i < keys.length; i++) {
            var key = keys[i];
            var value = obj[key];
            if (typeof value == 'object' && value !== null) {
                var index = cache.indexOf(value)
                if (index !== -1) {
                    hasCircle = true
                    break
                } else {
                    cache.push(value)
                    arguments.callee(value)
                    cache.pop()      //  注意:這里要推出數(shù)據(jù),因為遞歸返回,后面遍歷的屬性不是這個數(shù)據(jù)的子屬性
                }
            }
        }
    })(obj)

    return hasCircle
}

測試用例
/* 測試一 */

const obj = {
  foo: {
    name: 'foo',
    bar: {
      name: 'bar'
      baz: {
        name: 'baz',
        aChild: null  //待會讓它指向obj.foo
      }
    }
  }
}
obj.foo.bar.baz.aChild = obj.foo // foo->bar->baz->aChild->foo 形成環(huán)
/* 測試二 */

var obj = {
    foo: {
        name: 'foo',
        bar: {
            name: 'bar',
            baz: {
                name: 'baz',
                aChild: null
            }
        }
    },
    aaa: {
        name: "test",
        bbb: null
    }
}
obj.aaa.bbb = obj.foo;   //  aaa->bbb->bar->baz->aChild->null 不形成環(huán)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,699評論 19 139
  • 一、let 和 constlet:變量聲明, const:只讀常量聲明(聲明的時候賦值)。 let 與 var 的...
    dadage456閱讀 837評論 0 0
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 6,709評論 3 22
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 3,726評論 2 27
  • 基本用法 ES6 允許按照一定模式,從數(shù)組和對象中提取值,對變量進行賦值,這被稱為解構(gòu)(Destructuring...
    嘉奇呦_nice閱讀 833評論 0 2

友情鏈接更多精彩內(nèi)容