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

目录
  • 前言
  • JSON.stringify六大特性
    • 特性一
    • 特性二
    • 特性三
    • 特性四
    • 特性五
    • 特性六
  • 手动实现stringify
  • 总结

前言

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);
    };
};

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

总结

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

(0)

相关推荐

  • JSON.parse()和JSON.stringify()使用介绍

    parse用于从一个字符串中解析出json对象,如 var str = '{"name":"huangxiaojian","age":"23"}' 结果: JSON.parse(str) Object age: "23" name: "huangxiaojian" __proto__: Object 注意:单引号写在{}外,每个属性名都必须用双引号,否则会抛出异常. stringify(

  • JSON.stringify()方法讲解

    JSON.stringify()方法是什么呢? 我们在向服务器发送数据时一般是字符串. 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串. 语法 JSON.stringify(value[, replacer[, space]]) 参数说明: value: 必需,一个有效的 JSON 对象. replacer: 可选.用于转换结果的函数或数组. 如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值.使

  • 打印json对象的内容及JSON.stringify函数应用

    在调试的时候,经常需要知道json对象的内容,通过JSON.stringify函数,可以转换json对象为字符串. 复制代码 代码如下: $(document).ready(function() { $.ajax({ type: "post", dataType: "json", url: '/centermanage/modules/admin/index.php?task=getequipmentinfo', data: "&id="

  • 你可能不知道的JSON.stringify()详解

    前言 JSON已经逐渐替代XML被全世界的开发者广泛使用.本文深入讲解JavaScript中使用JSON.stringify的一些细节问题.首先简单回顾一下JSON和JavaScript: 不是所有的合法的JSON都是有效的JavaScript: JSON只是一个文本格式: JSON中的数字是十进制. 1. JSON.stringify let foo = { a: 2, b: function() {} }; JSON.stringify(foo); // "{ "a":

  • JSON.stringify 语法实例讲解

    认识javascript也不短的时间了,可是这个用法说实在的,我还是第一次见过,惭愧啊惭愧啊.于是乎,在网上找了写资料,写了些例子 希望能给园子们一些帮助. 作用:这个函数的作用主要是为了系列化对象的. 可能有些人对系列化这个词过敏,我的理解很简单.就是说把原来是对象的类型转换成字符串类型(或者更确切的说是json类型的).就这么简单.打个比方说,你有一个类,那么你可以通过这个方法转换成相应的json类型的.很简单吧. 接着看. 语法: JSON.stringify(value [, repla

  • 详解JSON.stringify()的5个秘密特性

    JSON.stringify() 方法能将一个 JavaScript 对象或值转换成一个 JSON 字符串. 作为一名 JavaScript 开发人员,JSON.stringify() 是用于调试的最常见函数.但是它的作用是什么呢,难道我们不能使用 console.log() 来做同样的事情吗?让我们试一试. //初始化一个 user 对象 const user = { "name" : "Prateek Singh", "age" : 26 }

  • js JSON.stringify()基础详解

    JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,如果指定了replacer是一个函数,则可以选择性的替换值,或者如果指定了replacer是一个数组,可选择性的仅包含数组指定的属性. 语法 JSON.stringify(value[, replacer [, space]]) 参数 value 将要序列化成 一个JSON 字符串的值. replacer 可选 如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函

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

    目录 前言 JSON.stringify六大特性 特性一 特性二 特性三 特性四 特性五 特性六 手动实现stringify 总结 前言 JSON.stringify是一个使用非常高频的API,但是其却存在一个特性,我们在使用的过程中需要留意这些特性以避免为代码程序埋雷,那么接下来便一起动手实现一个简易版本的jsonStringify函数 JSON.stringify六大特性 特性一 布尔值.数字.字符串的包装对象在序列化过程中会自动转换成对应的原始值 现在有这么一个对象: const obj

  • JSON.stringify实现深拷贝的巨坑详解

    目录 当对象中有时间类型的元素时候-----时间类型会被变成字符串类型数据 当对象中有undefined类型或function类型的数据时 --- undefined和function会直接丢失 当对象中有NaN.Infinity和-Infinity这三种值的时候 --- 会变成null 当对象循环引用的时候 --会报错 总结 当对象中有时间类型的元素时候-----时间类型会被变成字符串类型数据 const obj = { date:new Date() } typeof obj.date ==

  • JS JSON.stringify()的5个使用场景详解

    目录 前言 第二个参数replacer 为数组 第二个参数replacer 为函数 第三个参数为 Number 第三个参数为 String toJSON 方法 总结 前言 JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性. 语法如下: JSON.stringify(value[, replacer [, spac

  • Json转化为Java对象的实例详解

    Json转化为Java对象的实例详解 问题:前后端数据交互时,经常会遇到Json串与Java对象转化的问题,有的Java对象中还包含了List对象等. 解决方案: 引入 json-lib包,Maven坐标如下: <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> &l

  • highchart数据源纵轴json内的值必须是int(详解)

    var users = ["0","0","0","0","0","2","0"]; 这样的纵轴数据是不显示的,json里面的值必须是int类型. 必须是这样: var users = [1,1,1,1,1,1,1]; 难道不能自动转一下吗?还是我姿势不对,没有设置某个参数? 以上这篇highchart数据源纵轴json内的值必须是int(详解)就是小编分享给大家的全

  • Go语言基础Json序列化反序列化及文件读写示例详解

    目录 概述 JSON序列化 结构体转JSON map转JSON 切片转JSON JSON反序列化 JSON转map JSON转结构体 JSON转切片 写JSON文件 map写入JSON文件 切片写入JSON文件 结构体写入JSON文件 读JSON文件 解码JSON文件为map 解码JSON文件为切片 解码JSON文件为结构体 示例 概述 JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的.键值对的数据交换格式.结构由大括号'{}',中括

  • JSON Web Token(JWT)原理入门教程详解

    目录 一.跨域认证的问题 二.JWT 的原理 三.JWT 的数据结构 3.1 Header 3.2 Payload 3.3 Signature 3.4 Base64URL 四.JWT 的使用方式 五.JWT 的几个特点 六.参考链接 一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密码. 2.服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色.登录时间等等. 3.服务器向用户返回一个 session_id,写入用户的 Co

  • Go json自定义Unmarshal避免判断nil示例详解

    目录 前言 使用默认的 Unmarshal 方法 自定义的 Unmarshal 方法 前言 腾讯<Go安全指南>中提到[必须]nil指针判断:进行指针操作时,必须判断该指针是否为nil,防止程序panic,尤其在进行结构体Unmarshal时.但如果每次使用都要判断一下是否 nil 防止 panic的话,那么这样的代码就会比较麻烦,这里我们可以使用一个自定义的方法,来避免这种情况. 使用默认的 Unmarshal 方法 package main import ( "encoding/

  • Vue3.0版本强势升级点特性详解

    目录 一.Composition API: 组合API/注入API 二.自定义渲染API(Custom Renderer API) vue2.x架构问题 三.更先进的组件 Fragment组件 Suspense组件 四.更好的TS支持 五.更快的开发体验(vite开发构建工具) 六.按需编译,体积比Vue2.x更小(Tree shaking) 七.性能比2.x快1.2-2倍 diff算法的优化 render阶段的静态提升(render阶段指生成虚拟dom树的阶段) 事件侦听缓存 减少创建组件实例

随机推荐