JSON.stringify()還能這麼玩

對於JSON,相信大家應該都蠻熟悉的.不管是前端還是後端的童鞋,應該每天都會和JSON打交道吧.JSON是 JavaScript Object Notation(JavaScript對象表示法)的縮寫,是一種輕量級的文本數據交換格式,比xml更小,更快,更易於解析

在JavaScript中,JSON對象包含兩個方法,parse()stringify(),前者用於反序列化,後者用於序列化.所謂的序列化,通俗的理解就是將一個對象變成字符串,而反序列化就是相對應相反的過程.

今天我們主要來講講其中的stringify()方法.雖然我們平時也都在用這個方法,但是我們往往會忽略這個方法的更進一步的用法.假如我們能用好這個方法,在實際的開發過程中就可以達到事半功倍的效果.

相信大家在平時的開發過程中,經常會用到console.log來打印輸出結果.比如我們在下面打印一個對象:

let obj = {
  name:'zhangsan',
  age:undefined
}
console.log(obj)  // // {name: "zhangsan", age: undefined}

會過濾哪些屬性?

可以很清晰的在控制檯輸出結果,達到我們想要的結果.但是假如我們對象中的有的屬性值是沒有意義的.比如下面的代碼中,年紀是個未定義的屬性,我們不想要在控制檯輸出它該怎麼辦.這時就可以使用JSON.stringify()方法來達到過濾的目的

let obj = {
  name:'zhangsan',
  age:undefined
}
console.log(JSON.stringify(obj))  // {"name":"zhangsan"}

我們可以看到此時的輸出結果就已經把屬性值爲undefined這個age屬性給過濾掉了.而這正是JSON.stringify()的其中一個特性.除了undefined以外,屬性值爲任意函數或者symbol類型的,也會被過濾掉.

let obj = {
  name:'zhangsan',
  age:undefined,
  f:() => { console.log(1) },
  symbol:Symbol('This is a symbol')
}
console.log(JSON.stringify(obj))  // {"name":"zhangsan"}

我們再來給這個對象添加一個屬性.這次我們添加的是一個數組,而這個數組裏面就有一些上面我們提到過的這些類型,結果又是如何呢?

let obj = {
  name:'zhangsan',
  age:undefined,
  f:() => { console.log(1) },
  symbol:Symbol('This is a symbol'),
  arr:[1, undefined, 2, this.f, 3, Symbol('This is a symbol in array')]
}
console.log(JSON.stringify(obj))  // {"name":"zhangsan","arr":[1,null,2,null,3,null]}

可以看到,undefined,函數和symbol類型的都變成了null.
下面我們還要用這幾個類型來測試,假如我們直接使用JSON.stringify()來操作它們會怎麼樣呢?

console.log(JSON.stringify(undefined))  // undefined
console.log(JSON.stringify(() => { console.log(1) }))  // undefined
console.log(JSON.stringify(Symbol('This is a symbol')))  // undefined

可以看到輸出結果全是undefined.我們再來看看其他的某些特殊的值:

console.log(JSON.stringify(null))  // null
console.log(JSON.stringify(NaN))  // null
console.log(JSON.stringify(Infinity))  // null

可以看到null,NaN,Infinity之類的都變成了null.

下面我們來看看轉換包裝對象的結果

console.log(JSON.stringify(new String('str')))  // "str"
console.log(JSON.stringify(new Boolean(true)))  // true
console.log(JSON.stringify(new Number(1)))  // 1

可以看出字符串,布爾類型和數字的包裝對象會在序列化的時候變成原始值

toJSON()方法

假如我們轉換對象中有toJSON這個方法,那麼返回的結果就由它決定:

let obj = {
  name:'zhangsan',
  toJSON:function(){
    return 'customize return value'
  }
}
console.log(JSON.stringify(obj))  // "customize return value"

如果顯示的定義了toJSON方法卻沒有return任何內容,那麼結果就是undefined

let obj = {
  name:'zhangsan',
  toJSON:function(){}
}
console.log(JSON.stringify(obj))  // undefined

這裏又可以牽扯出另外一個對象類型Date.假如我們序列化一個Date類型,結果又是什麼呢?

console.log(JSON.stringify(new Date()))  // "2020-06-20T14:21:15.071Z"

可以看到輸出了這種我們熟悉的時間格式,這是因爲Date類型的對象就有自己的toJSON的實現

假如一個對象的屬性是不可枚舉的,那麼也會被過濾掉

let obj = Object.create({},{
  name:{
    value:'zhangsan',
    enumerable:false
  },
  age:{
    value:18,
    enumerable:true
  }
})
console.log(obj)  // {age: 18, name: "zhangsan"}
console.log(JSON.stringify(obj))  // {"age":18}

第二個參數

到上面爲止,我們舉例了一些JSON.stringify()的用法.很多人以爲到這裏就結束了,其實不是的,下面我們還要介紹它的第2個參數.

假如有這麼一個對象,它有姓名,性別,年紀等多種屬性.但是我們不想關心它的其他信息,只想知道它的名字是啥.而它的其他屬性值都不是像那些undefined等一樣是無意義的值,我們該如何過濾呢?

let obj = {
  name:'zhangsan',
  gender:'female',
  age:18,
  hobby:'swim'
}
console.log(JSON.stringify(obj,['age']))  // {"age":18}

這時,我們的第2個參數就派上用場了.我們傳入了一個數組,而這個數組中的值就是我們想要保留的屬性名,不在這個數組之列的,全部都不要返回.
除了傳入數組類型以外,我們還可以傳入一個函數.

let obj = {
  name:'zhangsan',
  gender:undefined,
  age:18,
  hobby:'swim'
}
console.log(JSON.stringify(obj, (key, value) => {
  if(typeof value === 'string'){
    return undefined
  }
  return value
}))  // {"age":18}

在函數中,我們做了一些邏輯判斷,當屬性值是字符串的時候,就給它過濾掉.使用這第二個參數,我們也可以改變屬性值爲undefined,symbol之類的原本不會返回的屬性.

let obj = {
  name:'zhangsan',
  gender:undefined,
  age:18,
  hobby:'swim'
}
console.log(JSON.stringify(obj, (key, value) => {
  if(typeof value === 'string'){
    return undefined
  }
  if(typeof value === 'undefined'){
    return 'not any more undefined'
  }
  return value
}))  // {"gender":"not any more undefined","age":18}

再來結合toString()這個方法,我們來輸出函數的具體內容:

let obj = {
  name:'zhangsan',
  f:function(){
    console.log('I\'m a function')
  }
}
console.log(JSON.stringify(obj, (key, value) => {
  if(typeof value === 'function'){
    return Function.prototype.toString.call(value)
  }
  return value
})) 
// {"name":"zhangsan","f":"function(){\n    console.log('I\\'m a function')\n  }"}

第三個參數

講完了第2個參數,我們再來講講第3個參數.是的,你沒有看錯,它還有第三個參數.這個參數的主要作用是用來美化輸出的json字符串.在沒有第三個參數的時候,我們輸出的字符串是擠在一堆的,不利於觀看.有了它,我們就可以格式化我們的輸出結果:

let obj = {
  name:'zhangsan',
  age:18,
  gender:'female'
}
console.log(JSON.stringify(obj,null,2))  
/*{
     "name": "zhangsan",
     "age": 18,
     "gender": "female"
}*/

第三個參數傳入的類型是數字n的話,就表示每一級比它的上一級多縮進n個空格,n最大爲10
第三個參數傳入的類型是字符串的話,則會在每一級前面加上這個字符串,字符串的最大長度也是10

let obj = {
  name:'zhangsan',
  age:18,
  gender:'female'
}
console.log(JSON.stringify(obj,null,'😊'))  
/*{
😊"name": "zhangsan",
😊"age": 18,
😊"gender": "female"
}*/

總結: 至此,關於JSON.stringify()的用法,我們基本講的差不多了.大部分的知識點我們就用下面的圖來表示了.
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章