功能比JSON.stringify强大的stringify(亲测好用)
Posted 乔碧萝·乔斯达
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了功能比JSON.stringify强大的stringify(亲测好用)相关的知识,希望对你有一定的参考价值。
介绍
写了一个能将对象或数组转换成字符串(内部能转义多种数据类型)的函数,供大家使用。
原理是把值转化为js代码字符串,再利用eval()函数把字符串转化为对象或数组,实现深拷贝。
使用场景:localStorage、sessionStorage存储及转换,各种局限于只能使用字符串存储或传递对象的场景。
例子:
const obj = {
a: NaN,
b: '',
c: true,
d(){
console.log('d')
},
e: async function*(){
consoel.log('e')
},
f: class {},
g: [],
h: new Map([[{}, []]]),
i: new Set([1,2,1,3]),
j: /^j$/g,
[Symbol('k')]: Symbol.for('k'),
l: 18n,
m: Math,
n: new ArrayBuffer(9)
}
const jsStr = stringify(obj)
console.log(jsStr)
/*
({a: NaN,b: '',c: true,d: function d() {
console.log('d')
},e: async function* () {
consoel.log('e')
},f: class A{ },g: [],h: new Map([[{}, []]]),i: new Set([1,2,3]),j: /^j$/g,l: 18n,m: Math,n: new ArrayBuffer(9),[Symbol('k')]: Symbol.for('k')})
*/
console.log(eval(jsStr)) // 输出复制后的源对象
以下是源代码(源代码简单易读):
/**
* 将数组或对象转化为字符串
*/
const typings = {
number: '[object Number]',
string: '[object String]',
boolean: '[object Boolean]',
symbol: '[object Symbol]',
bigInt: '[object BigInt]',
null: '[object Null]',
undefined: '[object Undefined]',
object: '[object Object]',
array: '[object Array]',
regExp: '[object RegExp]',
math: '[object Math]',
map: '[object Map]',
set: '[object Set]',
function: '[object Function]',
generator: '[object GeneratorFunction]',
async: '[object AsyncFunction]',
asyncGenerator: '[object AsyncGeneratorFunction]',
arrayBuffer: '[object ArrayBuffer]'
}
const classReg = /^class/
const arrowReg = /=\\>/
const funcReg = /^function/
const asyncFuncReg = /^async\\s+function/
const asyncGeneratorReg = /^async\\s+\\*function/
/**
* 主函数
* @param {object | array} val
* @returns {string}
*/
function stringify(val) {
const type = getType(val)
// 处理边界
if (
type !== typings.object &&
type !== typings.array
) {
throw new TypeError('Arguments are not arrays or objects')
}
return '(' + handler(val, type) + ')'
}
/**
* 处理器
* @param {any} val
* @param {string} type
* @returns {string}
*/
function handler(val, type) {
switch (type) {
case typings.number:
return createNum(val)
case typings.string:
return createStr(val)
case typings.boolean:
return createBool(val)
case typings.null:
return createNull()
case typings.undefined:
return createUndefined()
case typings.bigInt:
return createBigInt(val)
case typings.symbol:
return createSymbol(val)
case typings.function:
return createFunc(val)
case typings.generator:
return createGenerator(val)
case typings.async:
return createAsync(val)
case typings.asyncGenerator:
return createAsyncGenerator(val)
case typings.object:
return createObj(val)
case typings.array:
return createArr(val)
case typings.map:
return createMap(val)
case typings.set:
return createSet(val)
case typings.regExp:
return createRegExp(val)
case typings.math:
return createMath()
case typings.arrayBuffer:
return createBuffer(val)
default:
return
}
}
/**
* 创建函数
*/
function createNum(num) {
return num
}
function createStr(str) {
return `'${str}'`
}
function createBool(bool) {
return bool ? 'true' : 'false'
}
function createNull() {
return 'null'
}
function createUndefined() {
return 'undefined'
}
function createBigInt(bigInt) {
return bigInt.toString() + 'n'
}
function createSymbol(symbol) {
const description = symbol.description
const isFor = Symbol.for(description) === symbol
function isVoid(val) {
return val === undefined || val === ''
}
return isFor ? `Symbol.for(${isVoid(description) ? '' : `'${description}'`})` : `Symbol(${isVoid(description) ? '' : `'${description}'`})`
}
function createFunc(func) {
const funcStr = func.toString()
if (funcReg.test(funcStr) || arrowReg.test(funcStr) || classReg.test(funcStr)) {
return funcStr
} else {
return `function ${funcStr}`
}
}
function createGenerator(generator) {
const generatorStr = generator.toString()
return funcReg.test(generatorStr) ? generatorStr : `function ${generatorStr}`
}
function createAsync(asyncFunc) {
const asyncFuncStr = asyncFunc.toString()
if (asyncFuncReg.test(asyncFuncStr) || arrowReg.test(asyncFuncStr)) {
return asyncFuncStr
} else {
return asyncFuncStr.replace('async ', 'async function ')
}
}
function createAsyncGenerator(asyncGenerator) {
const asyncGeneratorStr = asyncGenerator.toString()
return asyncGeneratorReg.test(asyncGeneratorStr) ? asyncGeneratorStr : asyncGeneratorStr.replace('async *', 'async function*')
}
function createObj(obj) {
let start = '{'
let end = '}'
let res = ''
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
res += `${key}: ${handler(obj[key], getType(obj[key]))},`
}
}
const symbolList = Object.getOwnPropertySymbols(obj)
for (const symbol of symbolList) {
const symbolStr = createSymbol(symbol)
res += `[${symbolStr}]: ${handler(obj[symbol], getType(obj[symbol]))},`
}
return start + res.slice(0, -1) + end
}
function createArr(arr) {
let start = '['
let end = ']'
let res = ''
for (const item of arr) {
res += handler(item, getType(item)) + ','
}
return start + res.slice(0, -1) + end
}
function createMap(map) {
let start = 'new Map(['
let end = '])'
let res = ''
map.forEach((val, key) => {
res += `[${handler(key, getType(key))}, ${handler(val, getType(val))}],`
})
return start + res.slice(0, -1) + end
}
function createSet(set) {
let start = 'new Set('
let end = ')'
return start + createArr([...set]) + end
}
function createRegExp(regExp) {
return regExp
}
function createMath() {
return 'Math'
}
function createBuffer(arrayBuffer) {
return `new ArrayBuffer(${arrayBuffer.byteLength})`
}
/**
* 封装Object.toString方法
* @param {any} val
* @returns {string}
*/
function getType(val) {
return Object.prototype.toString.call(val)
}
以上是关于功能比JSON.stringify强大的stringify(亲测好用)的主要内容,如果未能解决你的问题,请参考以下文章
当我 JSON.stringify(object) 我得到一个疯狂的字符串作为值
qs.stringify、qs.parse、JSON.stringify的使用和区别