文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

简易版本JSON.stringify的实现及其六大特性详解

2024-04-02 19:55

关注

前言

JSON.stringify是一个使用非常高频的API,但是其却存在一个特性,我们在使用的过程中需要留意这些特性以避免为代码程序埋雷,那么接下来便一起动手实现一个简易版本的jsonStringify函数

JSON.stringify六大特性

特性一

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

现在有这么一个对象:


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

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


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

将其序列化stringify之后


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

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


const stringifyObj = JSON.parse(JSON.stringify(obj));
typeof stringifyObj.bol; // boolean
typeof stringifyObj.num; // number
typeof 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); // undefined
JSON.stringify(function () {}); // undefined
JSON.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 = p

JSON.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 (<anonymous>)

手动实现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);
    };
};


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完成,虽然能力尚欠缺许多,主要是提供一个思路,核心注释已注释在代码中,可结合代码和上文的特性一起理解

总结

到此这篇关于JSON.stringify实现及其六大特性详解的文章就介绍到这了,更多相关简易版本JSON.stringify及特性内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯