搜尋
首頁web前端js教程帶你了解JSON.stringify,看看怎麼使用

你真的會使用強大的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刪除
JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具