vlambda博客
学习文章列表

模拟JSON.stringfy三大参数

前端瓶子君
瓶子君,2021致力于帮助前端开启技术专项+算法之路!
39篇原创内容
Official Account

回复算法,加入前端编程面试算法每日一题群


来源:MSFee

https://juejin.cn/post/6952015403472125982

写在前面

编码的过程中常常需要对对象进行拷贝操作,一般单层对象使用Object.assign, 含有嵌套的话我都是直接JSON.parse(JSON.stringfy())一把梭,基本满足日常的开发需求了(当然主要是因为懒。。。)。久而久之,我突然对JSON.stringfy产生了好奇,打开MDN文档,好家伙。原来它可以接受三个参数。

模拟JSON.stringfy三大参数 于是我尝试自己来实现一个JSON.stringfy。

第一版:实现单层基本类型对象的拷贝

1.首先我们新建立一个index.ts文件,写入我们的代码

// 用于判断是字符串函数数字(目前我们只考虑字符串和数字两种类型)
const stringOrOtherVal = (data: string | number): string => {
    if (typeof data === 'string') {
        return `"${data}"`
    } else{
        return `${data}`
    }
}

const myStringfy = (params: any): string => {
    let resultStr = '{'
    for (let key in params) {
        resultStr += `"${key}":${stringOrOtherVal(params[key])},`
    }
    resultStr = resultStr.slice(0, resultStr.length - 1);
    resultStr += '}'
    return resultStr
}
复制代码

让我们来对比一下mystringfy和JSON.stringfy的功能

const obj = {
    name'张三',
    age15,
}

console.log(myStringfy1(obj))

console.log(JSON.stringify(obj))

console.log(JSON.stringify(obj) === myStringfy1(obj))
复制代码
模拟JSON.stringfy三大参数
image.png

我们已经实现了最基础的对象转字符串功能,不过这当然是远远不够的。

第二版,通过递归 实现嵌套对象的字符串转化

在这一版中我们需要实现嵌套对象的字符串转化功能(依然只包含字符串和数字类型)。改进我们的myStringfy函数

const myStringfy = (params: any): string => {
    let resultStr = '{'
    for (let key in params) {
        if (params[key] instanceof Object) {
            resultStr += `"${key}":${myStringfy(params[key])},`;
        } else {
            resultStr += `"${key}":${stringOrOtherVal(params[key])},`
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1);
    resultStr += '}'
    return resultStr
}
const obj = {
    name'张三',
    age15,
    dog: {
        size'large',
        food'骨头',
        dogType: {
            type1'哈士奇',
            nums3
        }
   }
}

console.log(myStringfy(obj))

console.log(JSON.stringify(obj))

console.log(JSON.stringify(obj) === myStringfy(obj))
复制代码
模拟JSON.stringfy三大参数
image.png

通过简单的递归,我们已经能够对嵌套对象进行转化,下面我们再来看看如果对象中存在数组该如何处理呢。

第三版 实现数组的字符串转化

对数组的处理步骤比较多,我们一方面需要判断数组中是否包含有对象,又或者是数组中嵌套有子数组等情况,所以我们将数组处理抽取为一个函数

const arrayDeail = (params: any[]): string => {
    let resultStr = '[';
    for (let i = 0; i < params.length; i++) {
        if (Array.isArray(params[i])) {
            resultStr += arrayDeail(params[i]) + ','
        } else if (params[i] instanceof Object) {
            resultStr += myStringfy(params[i]) + ',';
        } else {
            resultStr += stringOrOtherVal(params[i]) + ',';
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1)
    resultStr += ']'
    return resultStr
}
复制代码

上述代码中,通过遍历数组来处理数组中的每一个元素,同时判断类型,如果元素为数组,那么递归调用本身方法处理,如果为对象则调用myStringfy。

const myStringfy = (params: any): string => {
    let resultStr = '{'
    for (let key in params) {
        if (Array.isArray(params[key])) {
            resultStr += `"${key}":${arrayDeail(params[key])},`
        }else if (params[key] instanceof Object) {
            resultStr += `"${key}":${myStringfy(params[key])},`;
        }else {
            resultStr += `"${key}":${stringOrOtherVal(params[key])},`
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1);
    resultStr += '}'
    return resultStr
}

const obj = {
    name'张三',
    age15,
    arr: [1235'xxx', {
        tem: {
            name'测试',
            nums: [568],
        }
    }],
    dog: {
        size'large',
        food'骨头',
        dogType: {
            type1'哈士奇',
            nums3,
            large'ccc',
        }
   }
}
复制代码

改进一下我们的myStringfy,当对象属性为数组的时候,调用arrayDeail函数进行处理。用上面的obj测试一下

模拟JSON.stringfy三大参数 可以看到,也是没有任何问题的,实现到这一步,距离我们使用这个函数去转化我们的对象只差最后一步啦。

第四版 实现其他类型的处理 (null undefined function Map Set WeakMap WeakSet Date)

这里我们需要判断多种类型,而后面的Map、Set等也都属性引用类型,使用typeof就不再合适了,所以我们选择使用Object.prototype.toString.call()方法

const toStringCheckType = (params: any): string => {
    let resultStr = Object.prototype.toString.call(params);
    resultStr = resultStr.slice(1, resultStr.length - 1)
    const arr = resultStr.split(' ')
    return arr[1];
}
复制代码

我们新建立一个函数,对toString方法得到的结果简单的处理,处理后的函数可以直接准确的返回数据的对应类型。改进一下arrayDeail和myStringfy,以及上面最开始定义的stringOrOtherVal函数


const arrayDeail = (params: any[]): string => {
    let resultStr = '[';
    for (let i = 0; i < params.length; i++) {
        if (toStringCheckType(params[i]) === 'Array') {
            resultStr += arrayDeail(params[i]) + ','
        } else if (toStringCheckType(params[i]) === 'Object') {
            resultStr += myStringfy(params[i]) + ',';
        } else {
            resultStr += stringOrOtherVal(params[i]) + ',';
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1)
    resultStr += ']'
    return resultStr
}

const myStringfy = (params: any): string => {
    let resultStr = '{'
    for (let key in params) {
        if (toStringCheckType(params[key]) === 'Array') {
            resultStr += `"${key}":${arrayDeail(params[key])},`
        }
        else if (toStringCheckType(params[key]) === 'Object') {
            resultStr += `"${key}":${myStringfy(params[key])},`;
        } else if (toStringCheckType(params[key]) === 'Number' || toStringCheckType(params[key]) === 'String' || 
            toStringCheckType(params[key]) === 'Null' || toStringCheckType(params[key]) === 'Boolean') {
            resultStr += `"${key}":${stringOrOtherVal(params[key])},`
        } else if (toStringCheckType(params[key]) === 'Map' || toStringCheckType(params[key]) === 'Set' || 
            toStringCheckType(params[key]) === 'WeakMap' || toStringCheckType(params[key]) === 'WeakSet') {
            resultStr += `"${key}":{},`
        } else if(toStringCheckType(params[key]) === 'Date') {
            resultStr += `"${key}":"${params[key].toJSON()}",`
        } 
        else {
            continue
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1);
    resultStr += '}'
    return resultStr
}

const stringOrOtherVal = (data): string => {
    if (typeof data === 'string') {
        return `"${data}"`
    } else if (typeof data === 'number' || typeof data === 'boolean') {
        return `${data}`
    } else {
        return null
    }
}
复制代码

让我们来自测一下:

const obj = {
    name'张三',
    age15,
    ssstrue,
    arr: [1235'xxx', {
        tem: {
            name'测试',
            nums: [568],
        }
    }],
    mapnew Map(),
    setnew Set(),
    null_null,
    undefined_undefined,
    date_new Date(),
}
复制代码

模拟JSON.stringfy三大参数

当然啦,这样对其他类型的处理自然是不尽人意的,不过我们为了尽量的还原JSON.stringfy,先采用这种办法。到这里,我们基本上实现了JSON.stringfy的第一个参数的所有功能。

下面,让我们来实现第二个参数

第五版 JSON.stringify第二个参数replacer

首先,我们看看MDN文档上,对replacer的描述

模拟JSON.stringfy三大参数
image.png

可以看到,replacer可以是一个数组,也可以是一个函数,所以我们需要分别对数组和函数进行不同的处理。首先根据MDN文档,我们定义一下参数可能的类型

type replacerType = any[] | Function | undefined
复制代码

将新定义的replacerType和之前的toStringCheckType以及stringOrOtherVal抽取 出来,重新定义一个文件,来引入使用。

改进一下我们之前写的arrDetail函数和myStringfy函数

 const arrayDeail = (params: any[], replacer?: Function): string => {
    let resultStr = '[';
    let flag = toStringCheckType(replacer) === 'Function';
    for (let i = 0; i < params.length; i++) {
        params[i] = flag ? replacer(`${i}`, params[i]) : params[i]
        if (toStringCheckType(params[i]) === 'Array') {
            resultStr += flag ? arrayDeail(params[i], replacer) + ',' : arrayDeail(params[i]) + ','
        } else if (toStringCheckType(params[i]) === 'Object') {
            resultStr += myStringfy(params[i], replacer as replacerType) + ',';
        } else {
            resultStr += stringOrOtherVal(params[i]) + ',';
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1)
    resultStr += ']'
    return resultStr
}

const myStringfy = (params: any, replacer?: replacerType): string => {
    let resultStr: string = '{'
    let isFunction: number = 0// 1 表示函数 2 表示数组
    // 判断replacer 的类型
    if(toStringCheckType(replacer) === 'Function') {
        isFunction = 1;
    }else if(toStringCheckType(replacer) === 'Array'){
        isFunction = 2;
    }else if(toStringCheckType(replacer) === 'Undefined' || toStringCheckType(replacer) === 'Null') {

    }else {
        throw new Error("replacer 只能为函数、数组或者null!")
    }

    for (let key in params) {
        if(isFunction === 2 && (replacer as string[]).indexOf(key) === -1) { // 如果传递的是数组,判断当前key值是否在数组中
            continue
        }
        if(isFunction === 1) {
            params[key] = (replacer as Function)(key, params[key])
        }
        if (toStringCheckType(params[key]) === 'Array') {
            resultStr += isFunction === 1 ? `"${key}":${arrayDeail(params[key], replacer as Function)},` : `"${key}":${arrayDeail(params[key])},`
        }
        else if (toStringCheckType(params[key]) === 'Object') {
            resultStr += `"${key}":${myStringfy(params[key], replacer)},`;
        } else if (toStringCheckType(params[key]) === 'Number' || toStringCheckType(params[key]) === 'String' || 
            toStringCheckType(params[key]) === 'Null' || toStringCheckType(params[key]) === 'Boolean') {
            resultStr += `"${key}":${stringOrOtherVal(params[key])},`
        } else if (toStringCheckType(params[key]) === 'Map' || toStringCheckType(params[key]) === 'Set' || 
            toStringCheckType(params[key]) === 'WeakMap' || toStringCheckType(params[key]) === 'WeakSet') {
            resultStr += `"${key}":{},`
        } else if(toStringCheckType(params[key]) === 'Date') {
            resultStr += `"${key}":"${params[key].toJSON()}",`
        } 
        else {
            continue
        }
    }
    resultStr = resultStr.slice(0, resultStr.length - 1);
    resultStr += '}'
    return resultStr
}

复制代码

我们通过isFunction这个变量来区分函数还是数组,数组的话,需要判断对象的key值是否在数组中,如果不在则直接跳过。如果是函数的话,需要注意的是,我们要传递两个参数到如果是对象中的函数调用replacer函数中,一个是 key, 一个是value, 如果是对象中的函数调用replacer,那么key就是对应的下标。

这里需要注意的是,当 replacer 为函数的时候,第一次会把整个对象塞进去,一般来说,我们只需要这个对象中的属性和值就可以,不需要整个对象

到这里,我们终于实现出了第二个参数,虽然代码比较凌乱,不过不需要担心,我们先实现功能,后面再调整代码。让我们用个例子来测试一下:

当replacer为函数的时

const obj = {
    name'张三',
    age15,
    ssstrue,
    arr: [1235'xxx', {
        tem: {
            name'测试',
            nums: [568],
        }
    }],
}
function test(key, obj{
    if(typeof obj === 'number') {
        obj  = obj + 10;
    }
    return obj
}

console.log(myStringfy(obj, test))

console.log(JSON.stringify(obj, test))

console.log(JSON.stringify(obj, test) === myStringfy(obj, test))
复制代码

模拟JSON.stringfy三大参数 当replacer为数组时:

const keyArr = ['name''arr''nums']

console.log(myStringfy(obj, keyArr))

console.log(JSON.stringify(obj, keyArr))

console.log(JSON.stringify(obj, keyArr) === myStringfy(obj, keyArr))
复制代码
模拟JSON.stringfy三大参数
image.png

可以看到,我们的返回结果和JSON.stringfy的结果并不一样,是因为我对这里JSON.stringfy中数组中的对象是否需要判断在replacer存在不同的看法。不过这并不是太大的问题,我们继续往下看。

第六版 实现JSON.stringfy第三个参数

让我们看看MDN文档对,第三个参数的描述

模拟JSON.stringfy三大参数
image.png

可以看到,第三个参数space可以是数字也可以是字符串,如果是字符串的话,只会取前10个,让我们看看代码:

class Stringfy {
    addSpace: string = ''
    constructor(space) {
        this.addSpace = space;
    }
    arrayDeail = (params: any[], replacer?: Function, spaceStr?: string, count?: number, isObjFlag: boolean = true): string => {
        spaceStr = getPrefixStr(this.addSpace, count)
        const prefilxStr = !isObjFlag ? spaceStr.slice(0, spaceStr.length - this.addSpace.length) : ''
        let resultStr = prefilxStr + '[' + `${spaceStr.length ? '\n' : ''}`;
        let flag = toStringCheckType(replacer) === 'Function';
        for (let i = 0; i < params.length; i++) {
            params[i] = flag ? replacer(`${i}`, params[i]) : params[i]
            if (toStringCheckType(params[i]) === 'Array') {
                resultStr += flag ? this.arrayDeail(params[i], replacer, spaceStr, count + 1false) + ',' : this.arrayDeail(params[i], null, spaceStr, count + 1false) + ','
            } else if (toStringCheckType(params[i]) === 'Object') {
                resultStr += this.myStringfy(params[i], replacer as replacerType, spaceStr, count + 1) + ',';
            } else {
                resultStr += `${spaceStr}${stringOrOtherVal(params[i])}${spaceStr.length && i === params.length - 1 ? '' : ',' }${spaceStr.length ? '\n' : ''}`
            } 
        }
        resultStr = resultStr.slice(0, resultStr.length - 1)
        resultStr += spaceStr.length ? `\n${spaceStr.slice(0, spaceStr.length - this.addSpace.length)}` : ''
        resultStr +=  ']'
        return resultStr
    }

    myStringfy = (params: any, replacer?: replacerType, space?: string, count?: number, isObjFlag: boolean = true): string => {
        space = getPrefixStr(this.addSpace, count)
        const prefilxStr = isObjFlag ? space.slice(0, space.length - this.addSpace.length) : ''
        let resultStr: string = prefilxStr + '{' + `${space.length ? '\n' : ''}`
        let isFunction: number = checkReplacerType(replacer); // 1 表示函数 2 表示数组
        for (let key in params) {
            if (isFunction === 2 && (replacer as string[]).indexOf(key) === -1) { // 如果传递的是数组,判断当前key值是否在数组中
                continue
            }
            if (isFunction === 1) {
                params[key] = (replacer as Function)(key, params[key])
            }

            switch (toStringCheckType(params[key])) {
                case 'Array':
                    if(isFunction === 1) {
                        resultStr += `${space}"${key}":${this.arrayDeail(params[key], replacer as Function, space, count + 1)},${space.length ? '\n' : ''}`
                    }else if(isFunction === 2) {
                        resultStr += `${space}"${key}":${this.arrayDeail(params[key], null, space, count + 1)},${space.length ? '\n' : ''}`
                    }else {
                        resultStr += `${space}"${key}":${this.arrayDeail(params[key], null, space, count + 1)},${space.length ? '\n' : ''}`
                    }
                    break;
                case 'Object':
                    resultStr += `${space}"${key}":${this.myStringfy(params[key], replacer, space, count + 1false)},${space.length ? '\n' : ''}`;
                    break
                case 'Number':
                case 'String':
                case 'Null':
                case 'Boolean':
                    resultStr += `${space}"${key}":${stringOrOtherVal(params[key])},${space.length ? '\n' : ''}`
                    break
                case 'WeakMap':
                case 'Map':
                case 'Set':
                case 'WeakSet':
                    resultStr += `${space}"${key}":{},${space.length ? '\n' : ''}`
                    break
                case 'Date':
                    resultStr += `${space}"${key}":"${params[key].toJSON()}",${space.length ? '\n' : ''}`
                    break
                default:
                    continue
            }
        }
        resultStr = resultStr.slice(0, space.length ? resultStr.length - 2 : resultStr.length - 1);
        resultStr += space.length ? `\n${space.slice(0, space.length - this.addSpace.length)}` : ''
        resultStr += '}'
        return resultStr
    }
}
复制代码

可以看到我们重新定义了一个Stringfy类,因为我们需要保留最开始传递的space内容,同时优化了一下代码结构。同时在类型文件中新增了两个函数

export const checkSpaceType = (space?: string | number): string | never => {
    let spaceStr: string;
    if (toStringCheckType(space) === 'String') {
        if ((space as string).length > 10) {
            spaceStr = (space as string).slice(010)
        } else {
            spaceStr = space as string;
        }
    } else if (toStringCheckType(space) === "Number") {
        if (space > 10) {
            space = 10;
        }
        for (let i = 0; i < space; i++) {
            spaceStr += ' '
        }
    } else if (toStringCheckType(space) === 'Undefined') {
        spaceStr = '';
    } else {
        throw new Error("space 只能为数字或者字符串!")
    }
    return spaceStr
}

export const getPrefixStr = (str: string, count: number): string => {
    let resultStr = str;
    for(let i = 0; i < count; i++) {
        resultStr += str;
    }
    return resultStr
}
复制代码

checkSpaceType是用来判断第三个参数的类型,并且通过类型来生成相应的字符串。getPrefixStr的作用是用来生成填充的字符串。在定义myStringfy函数来实例化我们的Stringfy

const myStringfy = (params: any, replacer?: replacerType, space?: string | number): string => {
    let spaceStr = checkSpaceType(space)
    const stringfy = new Stringfy(spaceStr);
    return stringfy.myStringfy(params, replacer, spaceStr, 0)
}
复制代码

最后,让我们通过例子来测试一下:

console.log(myStringfy(obj, null'xxxxx'))

console.log(JSON.stringify(obj, null'xxxxx'))

复制代码
image.png

基本上可以看到结构是相同的。到这里我们基本上实现了JSON.stringfy的所有功能。

最终完整版代码如下:

typeAndFun.ts文件

export type replacerType = any[] | Function | undefined

export const toStringCheckType = (params: any): string => {
    let resultStr = Object.prototype.toString.call(params);
    resultStr = resultStr.slice(1, resultStr.length - 1)
    const arr = resultStr.split(' ')
    return arr[1];
}

export const stringOrOtherVal = (data): string => {
    if (typeof data === 'string') {
        return `"${data}"`
    } else if (typeof data === 'number' || typeof data === 'boolean') {
        return `${data}`
    } else {
        return null
    }
}

export const checkReplacerType = (replacer: replacerType): number | never => {
    let isFunction: number;
    // 判断replacer 的类型
    if (toStringCheckType(replacer) === 'Function') {
       return isFunction = 1;
    } else if (toStringCheckType(replacer) === 'Array') {
       return isFunction = 2;
    } else if (toStringCheckType(replacer) === 'Undefined' || toStringCheckType(replacer) === 'Null') {
        return 0
    } else {
        throw new Error("replacer 只能为函数、数组或者null!")
    }
}

export const checkSpaceType = (space?: string | number): string | never => {
    let spaceStr: string;
    if (toStringCheckType(space) === 'String') {
        if ((space as string).length > 10) {
            spaceStr = (space as string).slice(010)
        } else {
            spaceStr = space as string;
        }
    } else if (toStringCheckType(space) === "Number") {
        if (space > 10) {
            space = 10;
        }
        for (let i = 0; i < space; i++) {
            spaceStr += ' '
        }
    } else if (toStringCheckType(space) === 'Undefined') {
        spaceStr = '';
    } else {
        throw new Error("space 只能为数字或者字符串!")
    }
    return spaceStr
}

export const getPrefixStr = (str: string, count: number): string => {
    let resultStr = str;
    for(let i = 0; i < count; i++) {
        resultStr += str;
    }
    return resultStr
}
复制代码

index.ts文件

import {
    replacerType,
    toStringCheckType, stringOrOtherVal,
    checkReplacerType, checkSpaceType,
    getPrefixStr
from "./typeAndFun";

class Stringfy {

    addSpace: string = ''
    constructor(space) {
        this.addSpace = space;
    }
    arrayDeail = (params: any[], replacer?: Function, spaceStr?: string, count?: number, isObjFlag: boolean = true): string => {
        spaceStr = getPrefixStr(this.addSpace, count)
        const prefilxStr = !isObjFlag ? spaceStr.slice(0, spaceStr.length - this.addSpace.length) : ''
        let resultStr = prefilxStr + '[' + `${spaceStr.length ? '\n' : ''}`;
        let flag = toStringCheckType(replacer) === 'Function';
        for (let i = 0; i < params.length; i++) {
            params[i] = flag ? replacer(`${i}`, params[i]) : params[i]
            if (toStringCheckType(params[i]) === 'Array') {
                resultStr += flag ? this.arrayDeail(params[i], replacer, spaceStr, count + 1false) + ',' : this.arrayDeail(params[i], null, spaceStr, count + 1false) + ','
            } else if (toStringCheckType(params[i]) === 'Object') {
                resultStr += this.myStringfy(params[i], replacer as replacerType, spaceStr, count + 1) + ',';
            } else {
                resultStr += `${spaceStr}${stringOrOtherVal(params[i])}${spaceStr.length && i === params.length - 1 ? '' : ',' }${spaceStr.length ? '\n' : ''}`
            } 
        }
        resultStr = resultStr.slice(0, resultStr.length - 1)
        resultStr += spaceStr.length ? `\n${spaceStr.slice(0, spaceStr.length - this.addSpace.length)}` : ''
        resultStr +=  ']'
        return resultStr
    }

    myStringfy = (params: any, replacer?: replacerType, space?: string, count?: number, isObjFlag: boolean = true): string => {
        space = getPrefixStr(this.addSpace, count)
        const prefilxStr = isObjFlag ? space.slice(0, space.length - this.addSpace.length) : ''
        let resultStr: string = prefilxStr + '{' + `${space.length ? '\n' : ''}`
        let isFunction: number = checkReplacerType(replacer); // 1 表示函数 2 表示数组
        for (let key in params) {
            if (isFunction === 2 && (replacer as string[]).indexOf(key) === -1) { // 如果传递的是数组,判断当前key值是否在数组中
                continue
            }
            if (isFunction === 1) {
                params[key] = (replacer as Function)(key, params[key])
            }

            switch (toStringCheckType(params[key])) {
                case 'Array':
                    if(isFunction === 1) {
                        resultStr += `${space}"${key}":${this.arrayDeail(params[key], replacer as Function, space, count + 1)},${space.length ? '\n' : ''}`
                    }else if(isFunction === 2) {
                        resultStr += `${space}"${key}":${this.arrayDeail(params[key], null, space, count + 1)},${space.length ? '\n' : ''}`
                    }else {
                        resultStr += `${space}"${key}":${this.arrayDeail(params[key], null, space, count + 1)},${space.length ? '\n' : ''}`
                    }
                    break;
                case 'Object':
                    resultStr += `${space}"${key}":${this.myStringfy(params[key], replacer, space, count + 1false)},${space.length ? '\n' : ''}`;
                    break
                case 'Number':
                case 'String':
                case 'Null':
                case 'Boolean':
                    resultStr += `${space}"${key}":${stringOrOtherVal(params[key])},${space.length ? '\n' : ''}`
                    break
                case 'WeakMap':
                case 'Map':
                case 'Set':
                case 'WeakSet':
                    resultStr += `${space}"${key}":{},${space.length ? '\n' : ''}`
                    break
                case 'Date':
                    resultStr += `${space}"${key}":"${params[key].toJSON()}",${space.length ? '\n' : ''}`
                    break
                default:
                    continue
            }
        }
        resultStr = resultStr.slice(0, space.length ? resultStr.length - 2 : resultStr.length - 1);
        resultStr += space.length ? `\n${space.slice(0, space.length - this.addSpace.length)}` : ''
        resultStr += '}'
        return resultStr
    }
}

const obj = {
    arr: [1,2,[3,4,[5,6,[7,8]]]],
    data: [{
        ccc: {
            sddsd'xxx',
            arr: [1,2,3,4,5,6]
        },
        obk: {
            name'xxx',
            ahe21,
            tem: [12345,6,6]
        }
    }]
}



const myStringfy = (params: any, replacer?: replacerType, space?: string | number) => {
    let spaceStr = checkSpaceType(space)
    const stringfy = new Stringfy(spaceStr);
    console.log(stringfy.myStringfy(params, replacer, spaceStr, 0))
}

console.log(JSON.stringify(obj))
myStringfy(obj)

复制代码

到此我们基本实现JSON.stringfy的所有功能。

最后

欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿
回复「 算法 」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!
回复「交流」,吹吹水、聊聊技术、吐吐槽!
回复「 阅读 」,每日刷刷高质量好文!
如果这篇文章对你有帮助,在看」是最大的支持
前端瓶子君
瓶子君,2021致力于帮助前端开启技术专项+算法之路!
39篇原创内容
Official Account

“在看和转发” 就是最大的支持