千家信息网

如何实现简易版本JSON.stringify

发表于:2025-02-06 作者:千家信息网编辑
千家信息网最后更新 2025年02月06日,这篇文章主要介绍"如何实现简易版本JSON.stringify",在日常操作中,相信很多人在如何实现简易版本JSON.stringify问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希
千家信息网最后更新 2025年02月06日如何实现简易版本JSON.stringify

这篇文章主要介绍"如何实现简易版本JSON.stringify",在日常操作中,相信很多人在如何实现简易版本JSON.stringify问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何实现简易版本JSON.stringify"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

目录
  • 前言

  • JSON.stringify六大特性

    • 特性一

    • 特性二

    • 特性三

    • 特性四

    • 特性五

    • 特性六

  • 手动实现stringify

前言

JSON.stringify是一个使用非常高频的API,但是其却存在一个特性,我们在使用的过程中需要留意这些特性以避免为代码程序埋雷

JSON.stringify六大特性

特性一

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

现在有这么一个对象:

const obj = {    bol: new Boolean(true),    num: new Number(1),    str: new String(1)}

利用typeof检测obj各个属性的数据类型

typeof obj.bol; // objecttypeof obj.num; // objecttypeof obj.str; // object

将其序列化stringify之后

JSON.stringify(obj); // {"bol":true,"num":1,"str":"1"}

此时再将其解析parse进行各个属性的数据类型

const stringifyObj = JSON.parse(JSON.stringify(obj));typeof stringifyObj.bol; // booleantypeof stringifyObj.num; // numbertypeof stringifyObj.str; // string

特性二

NaN、Infinity、-Infinity以及null在序列化stringify时都会被当作null

const obj = {    nan: NaN,    infinity: Infinity,    null: null,};JSON.stringify(obj); // {"nan":null,"infinity":null,"null":null}

特性三

对象在序列化的时候,若是其存在toJSON函数,这个函数返回的值就是整个对象序列化后的结果

const obj = {    nan: NaN,    infinity: Infinity,    null: null,    toJSON() {        return "拥有toJSON函数";    },};JSON.stringify(obj); // "拥有toJSON函数"

可以看到序列化之后的数据仅存在toJSON函数的返回值,其余数据全部忽略

⚠️:Date数据会被正常序列化,因为Date上部署了toJSON函数,可以通过控制台打印Date.prototype.toJSON得知

const obj = {    date: new Date(),};JSON.stringify(obj); // {"date":"2021-10-08T11:43:31.881Z"}

特性四

表现不一的undefined、function和symbol

作为对象键值对时:

作为值:

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作为对象的key和value时,会在序列化时将其忽略

⚠️:此时可能会改变对象原有的顺序,因为上述三种数据会在序列化时被忽略

作为数组值时:

const arr = [undefined, function fn() {}, Symbol()];JSON.stringify(arr); // [null,null,null]

undefined、function和symbol作为数组的value时,会在序列化时将其都转换为null

单独存在时:

JSON.stringify(undefined); // undefinedJSON.stringify(function () {}); // undefinedJSON.stringify(Symbol()); // undefined

undefined、function和symbol单独存在时,会在序列化时都转换为undefined

特性五

序列化过程中,仅会序列化可枚举属性,不可枚举属性将会忽视

const obj = {    name: "nordon",    age: 18,};// 将age修改为不可枚举属性Object.defineProperty(obj, "age", {    enumerable: false,});JSON.stringify(obj); // {"name":"nordon"}

⚠️:此举也会改变对象的原有顺序

特性六

循环引用的对象,会在序列化时抛出异常

const obj = {    name: "nordon",    age: 18,};const p = {    name: 'wy',    obj}obj.p = pJSON.stringify(obj);

此时会导致控制台抛出异常:

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 ()

手动实现stringify

明白了JSON.stringify的一些特性,接下来便可以依据这些特性动手实现一个kack版本

在动手实现之前,先利用柯里化封装一些数据类型校验的工具函数:

const currying = (fn, ...outParams) => {    // 获取 fn 函数需要的参数个数    const paramsLen = fn.length;    return (...args) => {        // 收集全部参数        let params = [...outParams, ...args];        // 若参数没有达到 fn 需要的参数,继续收集参数        if (params.length < paramsLen) {            return currying(fn, ...params);        }        return fn(...params);    };};/** * type: 类型 - [object Array]、[object Number]等 * source: 数据源 */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函数, 直接使用 toJSON 返回的数据且忽略其他数据        return jsonStringify(data.toJSON());    } else if (Array.isArray(data)) {        let result = [];        //如果是数组,那么数组里面的每一项类型又有可能是多样的        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)) {        // 处理普通对象        let result = [];        Object.keys(data).forEach((item, index) => {            if (typeof item !== "symbol") {                //key 如果是 symbol 对象,忽略                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 可能是基础数据类型的情况在这里处理        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);    }}

到此,关于"如何实现简易版本JSON.stringify"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0