你可能不知道的JSON.stingify()

幾乎所有開發人員都會花一些時間在JavaScript上,有些時候是在使用JSON.stingify(以及與之相對應的,JSON.parse)。JSON - Javascript Object Notation - 已經成為許多開發人員理想的數據交換格式(the go-to data-interchange format)- 并且有許多語言支持序列化為JSON,而不僅僅只有JavaScript本身。如果哪天你半夜起來又無法入睡了,可以查一查關于JSON的歷史(tl;dr – Douglas Crockford is the brain behind it)

在寫JavaScript的時候,我們用JSON.stringify將某個值序列化為一個字符串值來表示一個對象。

JSON.stringify({
    name: "Jim Cowart",
    country: "Jimbabwe"
});
// 輸出結果:  "{"name":"Jim Cowart","country":"Jimbabwe"}"

JSON.stringify("Oh look, a string!");
// 輸出結果: ""Oh look, a string!""

JSON.stringify([1,2,3,4,"open","the","door"]);
// 輸出結果: "[1,2,3,4,"open","the","door"]"

我不會反復地討論關于序列化的規則,在這里你可以讀到更多相關的。但最基本的,你需要知道下面這些:

  • undefined 值、函數或者XML值會被忽略,除非當...
  • 如果你的數組當中含有 undefined值,函數或XML值,該數組中的這些值將會被當成 null

Let’s see about that:

JSON.stringify({
    doStuff: function() { },
    doThings: [ function() {}, undefined ]
});
// 輸出結果:  "{"doThings":[null,null]}"

"太棒了,Jim。我知道了。它是一種數據交換格式。而行為是不會被序列化的。這些天我使用的大多數庫都是在底層為我處理序列化(Most of the libraries I use these days handle serializing for me under the hood.)。那為什么要專門寫一篇post關于 JSON.stringify 呢?"

這個我知道,但是有一些實用的技巧遲早我們會需要用上的。Many of the larger applications I’ve worked on recently have had debug flags that can be flipped to enable various console logging from different components active on the page.
而我們明顯不希望總是通過無數行console.log來篩選信息 - 但當這變得有需要的時候,讓它的可讀性更高是不是更nice呢?

// what if this:
'{"name":"Jim Cowart","location":{"city":{"name":"Chattanooga","population":167674},"state":{"name":"Tennessee","abbreviation":"TN","population":6403000}},"company":"appendTo"}'

// could be formatted like this, automagically?
"{
    "name": "Jim Cowart",
    "location": {
        "city": {
            "name": "Chattanooga",
            "population": 167674
        },
        "state": {
            "name": "Tennessee",
            "abbreviation": "TN",
            "population": 6403000
        }
    },
    "company": "appendTo"
}"

事實上,JSON.stringify可以傳入3個參數(JSON.stringify(value [, replacer [, space]])。其中,第三個參數 - “space” - 允許你指定一個字符串字符、或者使用縮進、或是一個數字。如果你傳的是一個數字,那相應的空格數(最大為10)會被作為縮進量

var person = {
    name: "Jim Cowart",
    location: {
        city: {
            name: "Chattanooga",
            population: 167674
        },
        state: {
            name: "Tennessee",
            abbreviation: "TN",
            population: 6403000
        }
    },
    company: "appendTo"
};
//如果你希望縮進量為2 個空格,
// 你可以這么干:
JSON.stringify(person, null, 2);
/* produces:
"{
  "name": "Jim Cowart",
  "location": {
    "city": {
      "name": "Chattanooga",
      "population": 167674
    },
    "state": {
      "name": "Tennessee",
      "abbreviation": "TN",
      "population": 6403000
    }
  },
  "company": "appendTo"
}"
*/
// 如果你希望使用 tab 縮進,那么
// 你可以傳入 \t 作為第三個參數
// 以此來告別空格縮進
JSON.stringify(person, null, "\t");
/*輸出結果:
"{
    "name": "Jim Cowart",
    "location": {
        "city": {
            "name": "Chattanooga",
            "population": 167674
        },
        "state": {
            "name": "Tennessee",
            "abbreviation": "TN",
            "population": 6403000
        }
    },
    "company": "appendTo"
}"
*/

那么-第二個參數呢?在上面的例子中簡單地傳了一個null。關于 “replacer” 參數-它可以是一個數組或者是一個函數。如果是一個數組,它將只輸出你在該數組中所想要包含的keys。

// 假定 person對象是上一例子中的那個,
JSON.stringify(person, ["name", "company"], 4);
/* 輸出結果:
"{
    "name": "Jim Cowart",
    "company": "appendTo"
}"
*/

如果這 “replacer” 參數傳入的是一個函數,那么這個函數需要有兩個參數:key 和 value :

// a bit contrived, but it shows what's possible
// FYI - 被序列化的值是第一個傳給replacerFn的東西, 也即是這個對象的每一個key,因此需要檢查key的真假。
var replacerFn = function(key, value) {
    if(!key || key === 'name' || key === 'company') {
        return value;
    }
    return; //返回 undefined 并忽略 
}
JSON.stringify(person, replacerFn, 4);
/* produces:
"{
    "name": "Jim Cowart",
    "company": "appendTo"
}"
*/

你可以使用替換方法來處理得到 黑名單成員的姓名(與此相對應的是,使用白名單數組作為“replacer” 參數)。我發現這種方法是有用的,尤其當我需要迅速并且有針對性的得到一個DOM元素的值,但我希望阻止一個序列化循環引用的異常(當我drank some antifreeze 或是試圖做些荒謬的做法如JSON.stringify(document.body)的時候)。Feel free to browse this fiddle for a simple example of using a replacer function to blacklist based on member name(s).

當然,另一個得到自定義某個對象的JSON序列化的選擇是在對象中使用“toJSON”方法

var person = {
    name: "Jim Cowart",
    location: {
        city: {
            name: "Chattanooga",
            population: 167674
        },
        state: {
            name: "Tennessee",
            abbreviation: "TN",
            population: 6403000
        }
    },
    company: "appendTo",
    toJSON: function () {
        return {
            booyah : this.name + ' , employer: ' + this.company
        };
    }
};

// 上面的toJSON返回的值
// 實際上被字符串化的:
JSON.stringify(person, null, 4);
/* produces:
"{
    "booyah": "Jim Cowart , employer: appendTo"
}"
*/

“說真的,Jim。比起在控制臺寫更漂亮的JSON我們有更重要的事情要做。”

You don’t have to convince me, I’m with you 110%. 但我會說,當你為了調試已發布的信息的可視性或者logging websocket payloads而 wire-tapping a message bus 的時候更好看的JSON格式化會讓一切都不同。(囧 、o(╯□╰)o)能夠通過白名單替換數組(或者黑名單替換函數)來有選擇的序列化對象,可以很方便地在DOM元素/事件上幫助你跟蹤問題,或者簡單地讓你在復雜的交互上有更好的可視化,without de-railing you with serialization exceptions.

原文來自 Jim Cowart ,What You Might Not Know About JSON.stringify()

XguoX

  • Actually,其實這個在Nicholas C.Zakas的《JavaScript高級程序設計》第20章關于JSON的介紹講的也很詳細。比我這蹩腳翻譯要好得多。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容