目錄
三參數
#replacer
九特性
特性一: undefined、函数、Symbol值
特性二: toJSON() 方法
特性三: 布尔值、数字、字符串的包装对象
特性四: NaN Infinity null
特性五: Date对象
特性六: Symbol
特性七: BigInt
特性八: 循环引用
特性九: 可枚举属性
六妙用
localStorage
属性过滤
三思而后行之深拷贝
对象的 map 函数
删除对象属性
对象判断
数组对象去重
首頁 web前端 js教程 帶你了解JSON.stringify,看看怎麼使用

帶你了解JSON.stringify,看看怎麼使用

Mar 10, 2022 pm 07:37 PM
javascript

你真的會使用強大的JSON.stringify方法嗎?以下這篇文章帶大家詳細了解解JSON.stringify,介紹一下使用方法,希望對大家有幫助!

帶你了解JSON.stringify,看看怎麼使用

JSON.stringify 作為日常開發中常用的方法,你真的能靈活運用它嗎?

在學習本文之前,小包裝想讓大家帶著幾個問題,一起來深入學習 stringify 。 【相關推薦:javascript影片教學

  • stringify 函數有幾個參數,每個參數分別有啥用啊?
  • stringify 序列化準則有哪些啊?
    • 函數序列化中會如何處理?
    • null、undefined、NaN 等特殊的值又會如何處理?
    • ES6 後增加的Symbol 類型、BigInt 序列化過程中會有特別處理嗎?
  • stringify 為什麼不適合做深拷貝?
  • #你能想到那些stringify 的妙用?

#整篇文章的脈絡跟下面心智圖一致,大家可以先留一下印象。

帶你了解JSON.stringify,看看怎麼使用

三參數

在日常程式設計中,我們經常JSON.stringify 方法將某個對象轉換成JSON 字串形式。

const stu = {
    name: 'zcxiaobao',
    age: 18
}

// {"name":"zcxiaobao","age":18}
console.log(JSON.stringify(stu));
登入後複製

stringify 真的就這麼簡單嗎?我們先來看看 MDN 中對 stringify 的定義。

MDN 中指出: JSON.stringify() 方法將一個JavaScript 物件或值轉換為JSON# 字符串,如果指定了一個replacer 函數,則可以選擇性地替換值,或者指定的replacer 是數組,則可選擇性地僅包含數組指定的屬性。

看完定義,小套件就一驚,stringfy 不只一個參數嗎?當然了,stringify 有三個參數。

咱們來看一下 stringify 語法與參數介紹:

JSON.stringify(value[, replacer [, space]])
登入後複製
  • value: 將要序列後成 JSON 字串的值。
  • replacer(可選)
    • 如果該參數是一個函數,則在序列化過程中,被序列化的值的每個屬性都會經過該函數的轉換和處理;

    • 如果該參數是一個陣列,則只有包含在這個陣列中的屬性名稱才會被序列化到最終的JSON 字串中

    • 如果該參數為null 或未提供,則物件所有的屬性都會被序列化。

  • space(可選): 指定縮排用的空白字串,用於美化輸出
    • ##如果參數是個數字,它代表有多少的空格。上限為10。

    • 該值若小於1,則表示沒有空格

    • #如果該參數為字串(當字串長度超過10個字母,取其前10個字母),該字串將被作為空格

    • 如果該參數沒有提供(或為null),將沒有空格

#replacer

我們來試試看

replacer 的使用。

  • replacer 作為函數

#replacer 作為函數,它有兩個參數,鍵(key) 和值(value),並且兩個參數都會被序列化。

在開始時,

replacer 函數會被傳入一個空字串作為 key 值,代表著要被 stringify 的這個物件。要理解這點很重要,replacer 函數並非是上來就把物件解析成鍵值對形式,而是先傳入了待序列化物件。隨後每個物件或陣列上的屬性會被依序傳入。 如果函數傳回值為undefined或函數時,該屬性值會被篩選掉,其餘依照回傳規則。

// repalcer 接受两个参数 key value
// key value 分别为对象的每个键值对
// 因此我们可以根据键或者值的类型进行简单筛选
function replacer(key, value) {
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}
// function 可自己测试
function replacerFunc(key, value) {
  if (typeof value === "string") {
    return () => {};
  }
  return value;
}
const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
const jsonString = JSON.stringify(foo, replacer);
登入後複製

JSON 序列化結果為{"week":45,"month":7}

但如果序列化的是數組,若

replacer 函數傳回undefined 或函數,目前值不會被忽略,而將會被null 取代。

const list = [1, '22', 3]
const jsonString = JSON.stringify(list, replacer)
登入後複製

JSON 序列化的結果為'[1,null,3]'

  • replacer 作為陣列

作為數組比較好理解,過濾數組中出現的鍵值。

const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
const jsonString = JSON.stringify(foo, ['week', 'month']);
登入後複製

JSON 序列化结果为 {"week":45,"month":7}, 只保留 weekmonth 属性值。

九特性

特性一: undefined、函数、Symbol值

  • 出现在非数组对象属性值中: undefined、任意函数、Symbol 值在序列化过程中将会被忽略

  • 出现在数组中: undefined、任意函数、Symbol值会被转化为 null

  • 单独转换时: 会返回 undefined

// 1. 对象属性值中存在这三种值会被忽略
const obj = {
  name: 'zc',
  age: 18,
  // 函数会被忽略
  sayHello() {
    console.log('hello world')
  },
  // undefined会被忽略
  wife: undefined,
  // Symbol值会被忽略
  id: Symbol(111),
  // [Symbol('zc')]: 'zc',
}
// 输出结果: {"name":"zc","age":18}
console.log(JSON.stringify(obj));

// 2. 数组中这三种值会被转化为 null
const list = [
  'zc', 
  18, 
  // 函数转化为 null
  function sayHello() {
    console.log('hello world')
  }, 
  // undefined 转换为 null
  undefined, 
  // Symbol 转换为 null
  Symbol(111)
]

// ["zc",18,null,null,null]
console.log(JSON.stringify(list))

// 3. 这三种值单独转化将会返回 undefined

console.log(JSON.stringify(undefined))  // undefined
console.log(JSON.stringify(Symbol(111))) // undefined
console.log(JSON.stringify(function sayHello() { 
  console.log('hello world')
})) // undefined
登入後複製

特性二: toJSON() 方法

转换值如果有 toJSON() 方法,toJSON() 方法返回什么值,序列化结果就返回什么值,其余值会被忽略。

const obj = {
  name: 'zc',
  toJSON(){
    return 'return toJSON'
  }
}
// return toJSON
console.log(JSON.stringify(obj));
登入後複製

特性三: 布尔值、数字、字符串的包装对象

布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值

JSON.stringify([new Number(1), new String("zcxiaobao"), new Boolean(true)]);
// [1,"zcxiaobao",true]
登入後複製

特性四: NaN Infinity null

特性四主要针对 JavaScript 里面的特殊值,例如 Number 类型里的 NaNInfinity 及 null 。此三种数值序列化过程中都会被当做 null

// [null,null,null,null,null]
JSON.stringify([null, NaN, -NaN, Infinity, -Infinity])

// 特性三讲过布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
// 隐式类型转换就会调用包装类,因此会先调用 Number => NaN
// 之后再转化为 null
// 1/0 => Infinity => null
JSON.stringify([Number('123a'), +'123a', 1/0])
登入後複製

特性五: Date对象

Date 对象上部署了 toJSON 方法(同 Date.toISOString())将其转换为字符串,因此 JSON.stringify() 将会序列化 Date 的值为时间格式字符串

// "2022-03-06T08:24:56.138Z"
JSON.stringify(new Date())
登入後複製

特性六: Symbol

特性一提到,Symbol 类型当作值来使用时,对象、数组、单独使用分别会被忽略、转换为 null 、转化为 undefined

同样的,所有以 Symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们

const obj = {
  name: 'zcxiaobao',
  age: 18,
  [Symbol('lyl')]: 'unique'
}
function replacer(key, value) {
  if (typeof key === 'symbol') {
    return value;
  }
}

// undefined
JSON.stringify(obj, replacer);
登入後複製

通过上面案例,我们可以看出,虽然我们通过 replacer 强行指定了返回 Symbol 类型值,但最终还是会被忽略掉。

特性七: BigInt

JSON.stringify 规定: 尝试去转换 BigInt 类型的值会抛出 TypeError

const bigNumber = BigInt(1)
// Uncaught TypeError: Do not know how to serialize a BigInt
console.log(JSON.stringify(bigNumber))
登入後複製

特性八: 循环引用

特性八指出: 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误

日常开发中深拷贝最简单暴力的方式就是使用 JSON.parse(JSON.stringify(obj)),但此方法下的深拷贝存在巨坑,关键问题就在于 stringify 无法处理循环引用问题。

const obj = {
  name: 'zcxiaobao',
  age: 18,
}

const loopObj = {
  obj
}
// 形成循环引用
obj.loopObj = loopObj;
JSON.stringify(obj)

/* Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'loopObj' -> object with constructor 'Object'
    --- property 'obj' closes the circle
    at JSON.stringify (<anonymous>)
    at <anonymous>:10:6
*/
登入後複製

特性九: 可枚举属性

对于对象(包括 Map/Set/WeakMap/WeakSet)的序列化,除了上文讲到的一些情况,stringify 也明确规定,仅会序列化可枚举的属性

// 不可枚举的属性默认会被忽略
// {"age":18}
JSON.stringify(
    Object.create(
        null,
        {
            name: { value: &#39;zcxiaobao&#39;, enumerable: false },
            age: { value: 18, enumerable: true }
        }
    )
);
登入後複製

六妙用

localStorage

localStorage 对象用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。通常我们以对象形式进行存储。

  • 单纯调用 localStorage 对象方法

const obj = {
  name: &#39;zcxiaobao&#39;,
  age: 18
}
// 单纯调用 localStorage.setItem()

localStorage.setItem(&#39;zc&#39;, obj);

// 最终返回结果是 [object Object]
// 可见单纯调用localStorage是失败的
console.log(localStorage.getItem(&#39;zc&#39;))
登入後複製
  • localStorage 配合 JSON.stringify 方法

localStorage.setItem(&#39;zc&#39;, JSON.stringify(obj));

// 最终返回结果是 {name: &#39;zcxiaobao&#39;, age: 18}
console.log(JSON.parse(localStorage.getItem(&#39;zc&#39;)))
登入後複製

属性过滤

来假设这样一个场景,后端返回了一个很长的对象,对象里面属性很多,而我们只需要其中几个属性,并且这几个属性我们要存储到 localStorage 中。

  • 方案一: 解构赋值+ stringify

// 我们只需要 a,e,f 属性
const obj = {
  a:1, b:2, c:3, d:4, e:5, f:6, g:7
}
// 解构赋值
const {a,e,f} = obj;
// 存储到localStorage
localStorage.setItem(&#39;zc&#39;, JSON.stringify({a,e,f}))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem(&#39;zc&#39;))
登入後複製
  • 使用 stringifyreplacer 参数

// 借助 replacer 作为数组形式进行过滤
localStorage.setItem(&#39;zc&#39;, JSON.stringify(obj, [&#39;a&#39;,&#39;e&#39;,&#39;f&#39;]))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem(&#39;zc&#39;))
登入後複製

replacer 是数组时,可以简单的过滤出我们所需的属性,是一个不错的小技巧。

三思而后行之深拷贝

使用 JSON.parse(JSON.stringify) 是实现对象的深拷贝最简单暴力的方法之一。但也正如标题所言,使用该种方法的深拷贝要深思熟虑。

  • 循环引用问题,stringify 会报错

  • 函数、undefinedSymbol 会被忽略

  • NaNInfinity-Infinity 会被序列化成 null

  • ...

因此在使用 JSON.parse(JSON.stringify) 做深拷贝时,一定要深思熟虑。如果没有上述隐患,JSON.parse(JSON.stringify) 是一个可行的深拷贝方案。

对象的 map 函数

在使用数组进行编程时,我们会经常使用到 map 函数。有了 replacer 参数后,我们就可以借助此参数,实现对象的 map 函数。

const ObjectMap = (obj, fn) => {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function !`);
  }
  // 先调用 JSON.stringify(obj, replacer) 实现 map 功能
  // 然后调用 JSON.parse 重新转化成对象
  return JSON.parse(JSON.stringify(obj, fn));
};

// 例如下面给 obj 对象的属性值乘以2

const obj = {
  a: 1,
  b: 2,
  c: 3
}
console.log(ObjectMap(obj, (key, val) => {
  if (typeof value === "number") {
    return value * 2;
  }
  return value;
}))
登入後複製

很多同学有可能会很奇怪,为什么里面还需要多加一部判断,直接 return value * 2 不可吗?

上文讲过,replacer 函数首先传入的是待序列化对象,对象 * 2 => NaN => toJSON(NaN) => undefined => 被忽略,就没有后续的键值对解析了。

删除对象属性

借助 replacer 函数,我们还可以删除对象的某些属性。

const obj = {
  name: &#39;zcxiaobao&#39;,
  age: 18
}
// {"age":18}
JSON.stringify(obj, (key, val) => {
  // 返回值为 undefined时,该属性会被忽略 
  if (key === &#39;name&#39;) {
    return undefined;
  }
  return val;
})
登入後複製

对象判断

JSON.stringify 可以将对象序列化为字符串,因此我们可以借助字符串的方法来实现简单的对象相等判断。

//判断数组是否包含某对象
const names = [
  {name:&#39;zcxiaobao&#39;},
  {name:&#39;txtx&#39;},
  {name:&#39;mymy&#39;},
];
const zcxiaobao = {name:&#39;zcxiaobao&#39;};
// true
JSON.stringify(names).includes(JSON.stringify(zcxiaobao))
 
// 判断对象是否相等
const d1 = {type: &#39;div&#39;}
const d2 = {type: &#39;div&#39;}

// true
JSON.stringify(d1) === JSON.stringify(d2);
登入後複製

数组对象去重

借助上面的思想,我们还能实现简单的数组对象去重。

但由于 JSON.stringify 序列化 {x:1, y:1}{y:1, x:1} 结果不同,因此在开始之前我们需要处理一下数组中的对象。

  • 方法一: 将数组中的每个对象的键按字典序排列

arr.forEach(item => {
  const newItem = {};
  Object.keys(item)   // 获取对象键值
        .sort()       // 键值排序
        .map(key => { // 生成新对象
          newItem[key] = item[key];
        })
  // 使用 newItem 进行去重操作
})
登入後複製

但方法一有些繁琐,JSON.stringify 提供了 replacer 数组格式参数,可以过滤数组。

  • 方法二: 借助 replacer 数组格式

function unique(arr) {
  const keySet = new Set();
  const uniqueObj = {}
  // 提取所有的键
  arr.forEach(item => {
    Object.keys(item).forEach(key => keySet.add(key))
  })
  const replacer = [...keySet];
  arr.forEach(item => {
    // 所有的对象按照规定键值 replacer 过滤
    unique[JSON.stringify(item, replacer)] = item;
  })
  return Object.keys(unique).map(u => JSON.parse(u))
}

// 测试一下
unique([{}, {}, 
      {x:1},
      {x:1},
      {a:1},
      {x:1,a:1},
      {x:1,a:1},
      {x:1,a:1,b:1}
      ])

// 返回结果
[{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1,"b":1}]
登入後複製

【相关推荐:web前端

以上是帶你了解JSON.stringify,看看怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1269
29
C# 教程
1248
24
如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles