JSON 格式化对象,对象中存在函数的解决办法,JSON格式化函数
json在格式化对象是,如果是普通的键值对对象还是没有问题的,但是如果他的值是一个函数,在格式化之后,函数就会被剔除。
const a = {
name: '我爱你',
fn: function(){
console.log("我也爱你!")
}
};
const b = JSON.stringify(a);
当你输出变量b
的时候,你得到的会是:
"{\"name\":\"我爱你\"}"
fn不见了!
引用JSON.stringify()
方法描述中的一段解释:
undefined
、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成null
(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){})
orJSON.stringify(undefined)
可以知道,在非数组对象中的函数,会在转换过程中被忽略。这也就是导致fn消失的原因。
函数格式化方法
我们可以使用stringify的第二个参数,这个参数可以是一个函数,也可以是一个数组,官方的示意如下:
如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。
传入函数时,我们可以通过这个函数或者每次被转换的key和val值。
function对象本身存在一个toString
方法,toString()
方法返回一个表示当前函数源代码的字符串。
function sum(a, b) {
return a + b;
}
console.log(sum.toString());
//得到字符串格式: 'function sum(a, b) { return a + b; }'
那么这就够了。
const a = {
name: '我爱你',
fn: function(){
console.log("我也爱你!")
}
};
const b = JSON.stringify(a,function(key, val) {
if (typeof val === 'function') {
return val.toString();
}
return val;
});
console.log(b);
//{"name":"我爱你","fn":"function() {\n console.log(\"我也爱你!\")\n }"}
函数格式化完成。
函数格式化还原方法
函数格式化后,必然要还原使用,毕竟不可能永远是格式化,没有解析使用的。
但是字符串的解析,自然而然要用到字符转代码,绕不过去一个功能就是eval
,虽然可以用Function的特性,不使用eval,但是,终究,在string转成代码时,会触发运行,比如alert()
这些,就会被触发,这也导致了一个安全性的问题,你不知道你将要转化的内容,是否安全。
所以,这也是这些年来,为什么不推荐使用eval的原因。
怎么办?
目前es6的出现,可以很好的解决这个问题,我们可以自己建立一个沙箱机制,控制被转化的代码,运行时,只能获取我们允许的内容,不允许的,将禁止。
我们可以写一个粗浅的沙箱方法,将代码放置在沙箱中运行。
function sandBox(value) {
const withStr = `with(obj) { return ${ value } }`;
//创建监听对象
const proxy = new Proxy(Object.create(null), {
has(target, key) {
if (['console', 'Math', 'Date'].includes(key)) {
return target[key];
}
return true;
},
get(target, key) {
if (key === Symbol.unscopables) return undefined;
return target[key]
}
});
return new Function('obj', withStr)(proxy); //将监听的对象作为obj参数传入
};
创建一个没有原型的object对象也是一个无奈之举,为了安全,甚至不建议在这个obj对象里面添加属性,因为哪怕是基本的属性,string值这些,以及是有原型的,通过原型链,对方以及可以获取到你最外层的对象,做一些破坏性的事情。
这个沙箱不能说是绝对安全,但是目前来说,没有什么问题,以后有机会再折腾一下iframe沙箱方法吧。
在得到沙箱的方法后,我们解析就可以这样写:
const c = JSON.parse(b, function(key, val) {
if (/^function\s*\(.*\)\s*{/.test(val) || /^\(.*\)\s*=>/.test(val) || /^.*\s*\(.*\)\s*{/.test(val)) {
return sandBox(val);
}
return val;
});
c.fn(); //我也爱你!
至此,对象转字符加函数也转换的方法完成。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据