簡(jiǎn)易版本JSON.stringify的實(shí)現(xiàn)及其六大特性詳解
前言
JSON.stringify是一個(gè)使用非常高頻的API,但是其卻存在一個(gè)特性,我們?cè)谑褂玫倪^(guò)程中需要留意這些特性以避免為代碼程序埋雷,那么接下來(lái)便一起動(dòng)手實(shí)現(xiàn)一個(gè)簡(jiǎn)易版本的jsonStringify函數(shù)
JSON.stringify六大特性
特性一
布爾值、數(shù)字、字符串的包裝對(duì)象在序列化過(guò)程中會(huì)自動(dòng)轉(zhuǎn)換成對(duì)應(yīng)的原始值
現(xiàn)在有這么一個(gè)對(duì)象:
const obj = {
bol: new Boolean(true),
num: new Number(1),
str: new String(1)
}
利用typeof檢測(cè)obj各個(gè)屬性的數(shù)據(jù)類型
typeof obj.bol; // object typeof obj.num; // object typeof obj.str; // object
將其序列化stringify之后
JSON.stringify(obj); // {"bol":true,"num":1,"str":"1"}
此時(shí)再將其解析parse進(jìn)行各個(gè)屬性的數(shù)據(jù)類型
const stringifyObj = JSON.parse(JSON.stringify(obj)); typeof stringifyObj.bol; // boolean typeof stringifyObj.num; // number typeof stringifyObj.str; // string
特性二
NaN、Infinity、-Infinity以及null在序列化stringify時(shí)都會(huì)被當(dāng)作null
const obj = {
nan: NaN,
infinity: Infinity,
null: null,
};
JSON.stringify(obj); // {"nan":null,"infinity":null,"null":null}
特性三
對(duì)象在序列化的時(shí)候,若是其存在toJSON函數(shù),這個(gè)函數(shù)返回的值就是整個(gè)對(duì)象序列化后的結(jié)果
const obj = {
nan: NaN,
infinity: Infinity,
null: null,
toJSON() {
return "擁有toJSON函數(shù)";
},
};
JSON.stringify(obj); // "擁有toJSON函數(shù)"
可以看到序列化之后的數(shù)據(jù)僅存在toJSON函數(shù)的返回值,其余數(shù)據(jù)全部忽略
⚠️:Date數(shù)據(jù)會(huì)被正常序列化,因?yàn)镈ate上部署了toJSON函數(shù),可以通過(guò)控制臺(tái)打印Date.prototype.toJSON得知
const obj = {
date: new Date(),
};
JSON.stringify(obj); // {"date":"2021-10-08T11:43:31.881Z"}
特性四
表現(xiàn)不一的undefined、function和symbol
作為對(duì)象鍵值對(duì)時(shí):
作為值:
const obj = {
undefined: undefined,
fn() {},
symbol: Symbol()
};
JSON.stringify(obj); // {}
作為鍵:
const fn = function () {};
const obj = {
[undefined]: undefined,
[fn]: function () {},
[Symbol()]: Symbol()
};
JSON.stringify(obj); // {}
undefined、function和symbol作為對(duì)象的key和value時(shí),會(huì)在序列化時(shí)將其忽略
⚠️:此時(shí)可能會(huì)改變對(duì)象原有的順序,因?yàn)樯鲜鋈N數(shù)據(jù)會(huì)在序列化時(shí)被忽略
作為數(shù)組值時(shí):
const arr = [undefined, function fn() {}, Symbol()];
JSON.stringify(arr); // [null,null,null]
undefined、function和symbol作為數(shù)組的value時(shí),會(huì)在序列化時(shí)將其都轉(zhuǎn)換為null
單獨(dú)存在時(shí):
JSON.stringify(undefined); // undefined
JSON.stringify(function () {}); // undefined
JSON.stringify(Symbol()); // undefined
undefined、function和symbol單獨(dú)存在時(shí),會(huì)在序列化時(shí)都轉(zhuǎn)換為undefined
特性五
序列化過(guò)程中,僅會(huì)序列化可枚舉屬性,不可枚舉屬性將會(huì)忽視
const obj = {
name: "nordon",
age: 18,
};
// 將age修改為不可枚舉屬性
Object.defineProperty(obj, "age", {
enumerable: false,
});
JSON.stringify(obj); // {"name":"nordon"}
⚠️:此舉也會(huì)改變對(duì)象的原有順序
特性六
循環(huán)引用的對(duì)象,會(huì)在序列化時(shí)拋出異常
const obj = {
name: "nordon",
age: 18,
};
const p = {
name: 'wy',
obj
}
obj.p = p
JSON.stringify(obj);
此時(shí)會(huì)導(dǎo)致控制臺(tái)拋出異常:
Uncaught TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' | property 'p' -> object with constructor 'Object' --- property 'obj' closes the circle at JSON.stringify (<anonymous>)
手動(dòng)實(shí)現(xiàn)stringify
明白了JSON.stringify的一些特性,接下來(lái)便可以依據(jù)這些特性動(dòng)手實(shí)現(xiàn)一個(gè)kack版本
在動(dòng)手實(shí)現(xiàn)之前,先利用柯里化封裝一些數(shù)據(jù)類型校驗(yàn)的工具函數(shù):
const currying = (fn, ...outParams) => {
// 獲取 fn 函數(shù)需要的參數(shù)個(gè)數(shù)
const paramsLen = fn.length;
return (...args) => {
// 收集全部參數(shù)
let params = [...outParams, ...args];
// 若參數(shù)沒(méi)有達(dá)到 fn 需要的參數(shù),繼續(xù)收集參數(shù)
if (params.length < paramsLen) {
return currying(fn, ...params);
}
return fn(...params);
};
};
/**
* type: 類型 - [object Array]、[object Number]等
* source: 數(shù)據(jù)源
*/
const judgeType = (type, source) => {
return Object.prototype.toString.call(source) === type;
};
const isUndefined = currying(judgeType, "[object Undefined]");
const isSymbol = currying(judgeType, "[object Symbol]");
const isFunction = currying(judgeType, "[object Function]");
const isObject = currying(judgeType, "[object Object]");
const isNull = currying(judgeType, "[object Null]");
下面直接上代碼:
function jsonStringify(data) {
let type = typeof data;
if (isNull(data)) {
// null 直接返回 字符串'null'
return "null";
} else if (data.toJSON && typeof data.toJSON === "function") {
// 配置了 toJSON函數(shù), 直接使用 toJSON 返回的數(shù)據(jù)且忽略其他數(shù)據(jù)
return jsonStringify(data.toJSON());
} else if (Array.isArray(data)) {
let result = [];
//如果是數(shù)組,那么數(shù)組里面的每一項(xiàng)類型又有可能是多樣的
data.forEach((item, index) => {
if (isUndefined(item) || isSymbol(item) || isFunction(item)) {
result[index] = "null";
} else {
result[index] = jsonStringify(item);
}
});
result = "[" + result + "]";
return result.replace(/'/g, '"');
} else if (isObject(data)) {
// 處理普通對(duì)象
let result = [];
Object.keys(data).forEach((item, index) => {
if (typeof item !== "symbol") {
//key 如果是 symbol 對(duì)象,忽略
if (
data[item] !== undefined &&
typeof data[item] !== "function" &&
typeof data[item] !== "symbol"
) {
//鍵值如果是 undefined、function、symbol 為屬性值,忽略
result.push(
'"' + item + '"' + ":" + jsonStringify(data[item])
);
}
}
});
return ("{" + result + "}").replace(/'/g, '"');
} else if (type !== "object") {
let result = data;
//data 可能是基礎(chǔ)數(shù)據(jù)類型的情況在這里處理
if (Number.isNaN(data) || data === Infinity) {
//NaN 和 Infinity 序列化返回 "null"
result = "null";
} else if (isUndefined(data) || isSymbol(data) || isFunction(data)) {
// 由于 function 序列化返回 undefined,因此和 undefined、symbol 一起處理
return undefined;
} else if (type === "string") {
result = '"' + data + '"';
}
return String(result);
}
}
至此簡(jiǎn)易版本的JSON.stringify完成,雖然能力尚欠缺許多,主要是提供一個(gè)思路,核心注釋已注釋在代碼中,可結(jié)合代碼和上文的特性一起理解
總結(jié)
到此這篇關(guān)于JSON.stringify實(shí)現(xiàn)及其六大特性詳解的文章就介紹到這了,更多相關(guān)簡(jiǎn)易版本JSON.stringify及特性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JS中JSON.parse(JSON.stringify())實(shí)現(xiàn)深拷貝
- JavaScript語(yǔ)法 JSON序列化之stringify實(shí)例詳解
- JS中的Error對(duì)象及使用JSON.stringify()序列化Error問(wèn)題
- JSON stringify及parse方法實(shí)現(xiàn)數(shù)據(jù)深拷貝
- JavaScript對(duì)象與JSON格式的轉(zhuǎn)換及JSON.stringify和JSON.parse的使用方法
- 前端使用JSON.stringify實(shí)現(xiàn)深拷貝的巨坑詳解
- 學(xué)習(xí)JSON.stringify的9大特性和轉(zhuǎn)換規(guī)則
- 詳解JSON.parse和JSON.stringify用法
- JSON.stringify的多種用法總結(jié)
- 使用 JSON.stringify() 列化一個(gè)Error
相關(guān)文章
時(shí)間戳轉(zhuǎn)換為時(shí)間 年月日時(shí)間的JS函數(shù)
這篇文章介紹了時(shí)間戳轉(zhuǎn)換為時(shí)間 年月日時(shí)間的JS函數(shù),有需要的朋友可以參考一下2013-08-08
JavaScript截屏功能的實(shí)現(xiàn)代碼
我覺(jué)得使用JS截圖的想法是非?;闹嚨?,首先JS沒(méi)有權(quán)限調(diào)用操作系統(tǒng)的截圖功能,其次,瀏覽器(BOM)也沒(méi)有提供相關(guān)的截圖接口,經(jīng)過(guò)一番折騰,有點(diǎn)思路了,下面通過(guò)實(shí)例代碼給大家簡(jiǎn)單介紹下js 截屏功能的實(shí)現(xiàn)代碼,一起看看吧2017-07-07
微信小程序配置服務(wù)器提示驗(yàn)證token失敗的解決方法
這篇文章主要介紹了微信小程序配置服務(wù)器提示驗(yàn)證token失敗的解決方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04
npm安裝依賴時(shí)出現(xiàn)Peer Dependencies沖突報(bào)錯(cuò)解決分析
這篇文章主要為大家介紹了npm安裝依賴時(shí)出現(xiàn)Peer Dependencies沖突報(bào)錯(cuò)解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
JS代碼實(shí)現(xiàn)根據(jù)時(shí)間變換頁(yè)面背景效果
這篇文章主要介紹了JS代碼實(shí)現(xiàn)根據(jù)時(shí)間變換頁(yè)面背景效果的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友一起看下吧2016-06-06
JavaScript回調(diào)(callback)函數(shù)概念自我理解及示例
此文適合JavaScript入門級(jí)選手閱讀,在JavaScript里什么叫Callback“回調(diào)函數(shù)”,把方法b當(dāng)做一個(gè)參數(shù)傳遞個(gè)方法a,當(dāng)方法a執(zhí)行完后執(zhí)行另外一個(gè)指定函數(shù)(這里是b函數(shù)),感興趣的朋友可以了解下哈2013-07-07
JavaScript中async和await的使用及隊(duì)列詳情
這篇文章主要介紹了JavaScript中async和await的使用及隊(duì)列詳情,主要圍繞js中async和await簡(jiǎn)單解析展開(kāi)面試中可能會(huì)問(wèn)到的關(guān)于隊(duì)列的一些場(chǎng)景和知識(shí)點(diǎn),需要的朋友可以參考一下2022-07-07
微信小程序中進(jìn)行地圖導(dǎo)航功能的實(shí)現(xiàn)方法
這篇文章主要介紹了微信小程序中進(jìn)行地圖導(dǎo)航功能的實(shí)現(xiàn)方法,需要的朋友可以參考下2018-06-06

