你不知道的JavaScript中的5個JSON祕密功能

前端小智發表於2022-03-17
作者: Siddharth
譯者:前端小智
來源:dev

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

在開發中,我們會經常使用 JSON.stringify(object) 來序列化物件,但JSON.stringify方法除了了第一個引數外,還有其它引數可用,今天我們一起來看看這些引數是做啥的,Let's 開始。

1. 格式化

預設的 JSON.stringify(object) 出來資料是一行字串,這看起來很醜,如下所示:

const user = {
  name: '小智',
  age: 30,
  isAdmin: true,
  friends: ['隔壁老王', '小可愛'],
  address: {
    city: '天上人間',
  },
}
console.log(JSON.stringify(user))
// {"name":"小智","age":30,"isAdmin":true,"friends":["隔壁老王","小可愛"],"address":{"city":"天上人間"}}

JSON.stringify也有一個內建的格式化器!

console.log(JSON.stringify(user, null, 2))

{
  "name": "小智", 
  "age": 30,      
  "isAdmin": true,
  "friends": [
    "隔壁老王",
    "小可愛"
  ],
  "address": {
    "city": "天上人間"
  }
}

(如果你想知道這個 null 是什麼,我們以後再談)。

在這個例子中,JSON的格式化有2個空格的縮排。我們還可以指定一個自定義字元,用於縮排。

console.log(JSON.stringify(user, null, '【二哈】'))

{
【二哈】"name": "小智",
【二哈】"age": 30,
【二哈】"isAdmin": true,
【二哈】"friends": [
【二哈】【二哈】"隔壁老王",
【二哈】【二哈】"小可愛"
【二哈】],
【二哈】"address": {
【二哈】【二哈】"city": "天上人間"
【二哈】}
}

2. 在序列化的資料中隱藏某些屬性

JSON.stringify 還有一個很少有人知道的第二個參,稱為 replacer,是一個函式或陣列,決定哪些資料要保留在輸出中,哪些不要。

舉例一,假如,我們想隱藏使用者的密碼欄位,可以這麼做:

const user = {
  name: '小智',
  password: '12345',
  age: 30
};


console.log(JSON.stringify(user, (key, value) => {
  if (key === 'password') {
    return
  }
  return value
}))

輸出:

{"name":"小智","age":30}

我們可以進一步重構:

function  stripKeys (...keys) {
  return (key, value) => {
    if (keys.includes(key)) return 
    return value
  }
}
const user = {
  name: '小智',
  password: '12345',
  age: 30,
  gender: '未知'
};


console.log(JSON.stringify(user, stripKeys('password', 'gender')))

輸出:

{"name":"小智","age":30}

你也可以傳遞一個陣列:

const user = {
  name: '小智',
  password: '12345',
  age: 30
}

console.log(JSON.stringify(user, ['name', 'age']))

輸出:

{"name":"小智","age":30}

最酷的是這對陣列也有效,假設有如下的陣列:

const poetry = [
  {
    name: '小智',
    content: [
      '興盡晚回舟,誤入藕花深處。',
      '鬼畜,鬼畜,單身百年手速。',
      '起點太高,於是期待太多,奢求太過,所以永不滿足。',
    ],
    tags: ['經典', '魔幻', '鬼才'],
  },
  {
    name: '王大志',
    content: [
      '君子無非就是有耐心的狼。',
      '信者,無需誓言,不信者,誓言亦無助。'
    ],
    tags: ['經典', '魔幻', '鬼才'],
  },
]

由於詩太過美麗,我想出名,最後輸出就想打出輸出關於名字的欄位,那麼也可以使用 JSON.stringify 來做:

console.log(JSON.stringify(poetry, ['name']))

輸出:

[{"name":"小智"},{"name":"王大志"}]

漂亮!

3. 使用 toJSON 來建立自定義輸出格式

如果一個物件實現了 toJSON 函式,JSON.stringify 將使用它來串化資料。

考慮一下這個例子:

class Fraction {
  constructor(n, d) {
    this.numerator = n;
    this.denominator = d;
  }
}

console.log(JSON.stringify(new Fraction(1, 2)))

輸出:

{"numerator":1,"denominator":2}

如果我們想讓輸出的結果是 1/2,那要怎麼做呢?實現 toJSON 方法。

class Fraction {
  constructor(n, d) {
    this.numerator = n;
    this.denominator = d;
  }

  toJSON() {
      return `${this.numerator}/${this.denominator}`
  }
}

console.log(JSON.stringify(new Fraction(1, 2)))

JSON.stringify 根據 toJSON 方法來解析,所以結果是 1/2

4. 恢復資料

繼續上面的例子,如果我們想再次解析JSON時,分數會神奇被還原成原來的物件,這是不是很酷?我們可以這樣做:

class Fraction {
  constructor(n, d) {
    this.numerator = n;
    this.denominator = d;
  }

  toJSON() {
      return `${this.numerator}/${this.denominator}`
  }

  static fromJSON(key, value) {
    if (typeof value === 'string') {
        const parts = value.split('/').map(Number);
        if (parts.length === 2) return new Fraction(parts);
    }

    return value;
  }
}

const fraction = new Fraction(1, 2);
const stringified = JSON.stringify(fraction);
console.log(stringified);
// "1/2"
const revived = JSON.parse(stringified, Fraction.fromJSON);
console.log(revived);
// Fraction { numerator: 1, denominator: 2 }

我們可以向 JSON.parse 傳遞第二個引數來指定一個 reviver 函式。reviver 的工作是將字串化的資料 "恢復"到它的原始形式。在這裡,我們傳遞了一個reviver,它是 Fraction 類的靜態方法 fromJSON

有趣的是:這個功能在內建的Date物件中使用。試著查一下 Date.prototype.toJSON

console.log(JSON.stringify(new Date()))
//=> '"2022-03-01T06:28:41.308Z"'

為了恢復日期,我們可以使用 JSON.parse

function reviveDate(key, value) {
    const regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,}|)Z$/;

    if (typeof value === "string" && regex.test(value)) {
        return new Date(value);
    }

    return value;
}
console.log(JSON.parse('"2022-03-01T06:28:41.308Z"', reviveDate))
//=> Tue Mar 01 2022 06:28:41 GMT-0700 (Pacific Daylight Time)

5.使用 revivers 隱藏資料

stringify 一樣,parse也可以用來隱藏資料。它們工作方式是一樣的:

const user = JSON.stringify({
  name: '小智',
  password: '12345',
  age: 30,
})

console.log(
  JSON.parse(user, (key, value) => {
    if (key === 'password') return
    return value
  })
)

輸出:

{ name: '小智', age: 30 }

如果你知道任何其他很酷的JSON技巧,請告訴我 ?!

完,我是刷碗智,新的一年,我們一起刷刷刷。


原文:https://dev.to/siddharhshynib...

編輯中可能存在的bug沒法實時知道,事後為了解決這些bug,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章