前言
平时工作中真的忽略了对这些经典方法的学习,继续加油吧,工作和生活本身也是一个持续学习的过程(ps:一定要走出舒适圈,多出去面试,会发现,自己比想象中的自己更菜)。
先复习一下基本的东西
参考: MDN 但是我更喜欢看高程,可能是讲的比较通俗易懂吧。
可以序列化的类型
- 简单类型:字符串、数值、布尔值和null。undefined会被忽略 、NaN和Infinity格式的数值类型会被序列化为null.
- 复杂类型:对象和数组。其中属性的值既可以是简单类型也可以是复杂类型。 看看MDN上面的列子,比较全
JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify("foo"); // '"foo"'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify({ x: 5 }); // '{"x":5}'
JSON.stringify(NaN); //null
JSON.stringify(Infinity); //null
JSON.stringify(function(){}); //undefined
JSON.stringify(undefined); //undefined
JSON.stringify({x: 5, y: 6});
// "{"x":5,"y":6}"
JSON.stringify([new Number(1), new String("false"), new Boolean(false)]);
// '[1,"false",false]'
JSON.stringify({x: undefined, y: Object, z: Symbol("")});
// '{}' 值为undefined、Object、Symbol的属性,在转化的时候会被忽略
JSON.stringify([undefined, Object, Symbol("")]);
// '[null,null,null]'
JSON.stringify({[Symbol("foo")]: "foo"});
// '{}' 属性值为Symbol也会被忽略
JSON.stringify({[Symbol.for("foo")]: "foo"}, [Symbol.for("foo")]);
// '{}'
JSON.stringify(
{[Symbol.for("foo")]: "foo"},
function (k, v) {
if (typeof k === "symbol"){
return "a symbol";
}
}
);
// undefined
// 不可枚举的属性默认会被忽略:
JSON.stringify(
Object.create(
null,
{
x: { value: 'x', enumerable: false },
y: { value: 'y', enumerable: true }
}
)
);
// "{"y":"y"}"
参数
- 序列化的对象
- 过滤器(数组或函数)
- 用于缩进结果的JSON字符串中的选项
//第二个参数是数组的情况
let book = {
title:'Professional Javascript',
authors:[
"Nicholas c. Zakes",
"Matt Frisbie"
],
edition:4,
year:2017
}
let jsonText = JSON.stringify(book,['title','edition']);
console.log(jsonText)//{"title":"Professional Javascript","edition":4}
//第二个参数是函数的情况
let book = {
title: 'Professional Javascript',
authors: [
"Nicholas c. Zakes",
"Matt Frisbie"
],
edition: 4,
year: 2017
}
let jsonText = JSON.stringify(book, function (key, value) {
switch (key) {
case 'authors':
return value.join(",");
case "year":
return 5000;
case 'edition':
return undefined;
default:
return value;
}
})
console.log(jsonText)//{"title":"Professional Javascript","authors":"Nicholas c. Zakes,Matt Frisbie","year":5000}
toJSON方法 原生Date上面就有一个toJSON方法,能够自动将JS的Date对象转化为ISO 8601日期字符串
let book = {
title:'professional javascript',
authors:[
"nicholas c zakes",
"natt frisbie"
],
edition:4,
year:2017,
toJSON:function(){
return this.title
}
}
let jsonText = JSON.stringify(book);
console.log(jsonText)//"professional javascript"
可以开始实现了
此版本没有考虑后面几个参数的情况。
第一版:先考虑基本类型
根据上面的分析基本类型中NaN、Infinity undefined symbol 存在特殊情况,需要特殊处理。
function imitateJSONstringfiy(val) {
let dataType = typeof val;
let result = '';
if (dataType != 'object') {
//特殊判断number中的NaN和Infinity
if (Number.isNaN(val) || val === Infinity || val === -Infinity) {
result = 'null'
} else if (dataType == 'undefined' || dataType == 'Function' || dataType == 'Symbol') { //特殊判断undefined function symbol类型
result = 'undefined'
} else if (dataType == 'string') {//字符串类型会用引号引起来
result = '"' + val + '"'
} else {
result = String(val)
}
return result
} else {
}
}
第二版考虑复杂类型
考虑null直接返回null
考虑数组
分析:
- 数组里面可能还存在其他类型
- 数组还存在嵌套
function imitateJSONstringfiy(val) {
let dataType = typeof val;
let result = '';
if (dataType != 'object') {
//特殊判断number中的NaN和Infinity
if (Number.isNaN(val) || val === Infinity || val === -Infinity) {
result = 'null'
} else if (dataType == 'undefined' || dataType == 'unction' || dataType == 'symbol') { //特殊判断undefined function symbol类型
result = 'undefined'
} else if (dataType == 'string') {//字符串类型会用引号引起来
result = '"' + val + '"'
} else {
result = String(val)
}
return result
} else {
if (val == null) {
return 'null'
} else if (Object.prototype.toString.call(val) == '[object Array]') {//判断是否是数组类型
let result = []
val.forEach((item, index) => {
result[index] = imitateJSONstringfiy(item)
})
result = "'[" + result.join(',') + "]'"
console.log(result)
}
}
}
imitateJSONstringfiy([undefined, undefined])
imitateJSONstringfiy([undefined, NaN])
考虑对象类型
- 要考虑键值特殊的情况 undefined NaN Infinity之类的键和值都会被忽略
function imitateJSONstringfiy(val) {
let dataType = typeof val;
let result = '';
if (dataType != 'object') {
//特殊判断number中的NaN和Infinity
if (Number.isNaN(val) || val === Infinity || val === -Infinity) {
result = 'null'
} else if (dataType == 'undefined' || dataType == 'function' || dataType == 'symbol') { //特殊判断undefined function symbol类型
result = 'undefined'
} else if (dataType == 'string') {//字符串类型会用引号引起来
result = '"' + val + '"'
} else {
result = String(val)
}
return result
} else {
if (val == null) {
return 'null'
} else if (Object.prototype.toString.call(val) == '[object Array]') {//判断是否是数组类型
let result = []
val.forEach((item, index) => {
result[index] = imitateJSONstringfiy(item)
})
result = "'[" + result + "]'"
return (result).replace(/'/g, '"');
} else { //对象
let result = [];
Object.keys(val).forEach((item, index) => {
if (typeof item != 'symbol' && val[item] !== undefined && typeof val[item] !== 'function'
&& typeof val[item] !== 'symbol') {//键或者值为这几种类型的话会被忽略
result.push('"' + item + '"' + ":" + imitateJSONstringfiy(val[item]));
}
})
return ("{" + result + "}").replace(/'/g, '"');
}
}
}
// imitateJSONstringfiy([undefined, undefined])
// imitateJSONstringfiy([1, 2, [1, 2]])
imitateJSONstringfiy({a:1,b:2})
用MDN上面的例子来试试
console.log(imitateJSONstringfiy({}))// true
console.log(imitateJSONstringfiy(true))// true
console.log(imitateJSONstringfiy("foo"))//"foo"
console.log(imitateJSONstringfiy([1, "false", false]))//"[1,"false",false]"
console.log(imitateJSONstringfiy({ x: 5 }))// {"x":5}
console.log(imitateJSONstringfiy(NaN))//null
console.log(imitateJSONstringfiy(Infinity))//null
console.log(imitateJSONstringfiy(function () { }))//undefined
console.log(imitateJSONstringfiy(undefined))//undefined
console.log(imitateJSONstringfiy({ x: 5, y: 6 }))//{"x":5,"y":6}
console.log(imitateJSONstringfiy([new Number(1), new String("false"), new Boolean(false)]))//"[{},{"0":"f","1":"a","2":"l","3":"s","4":"e"},{}]"
console.log(imitateJSONstringfiy({ x: undefined, y: Object, z: Symbol("") }))//{}
console.log(imitateJSONstringfiy([undefined, Object, Symbol("")]))//"[undefined,undefined,undefined]"
console.log(imitateJSONstringfiy({ [Symbol("foo")]: "foo" }))//{}
// console.log(imitateJSONstringfiy({[Symbol.for("foo")]: "foo"}))
console.log(imitateJSONstringfiy({ [Symbol.for("foo")]: "foo" },//{}
function (k, v) {
if (typeof k === "symbol") {
return "a symbol";
}
}))
这个返回的结果和预期的不同
console.log(imitateJSONstringfiy([new Number(1), new String("false"), new Boolean(false)]))//"[{},{"0":"f","1":"a","2":"l","3":"s","4":"e"},{}]"
最终代码
这里特殊处理了一下这三种类型
function imitateJSONstringfiy(val) {
let dataType = typeof val;
let result = '';
if (dataType != 'object') {
//特殊判断number中的NaN和Infinity
if (Number.isNaN(val) || val === Infinity || val === -Infinity) {
result = 'null'
} else if (dataType == 'undefined' || dataType == 'function' || dataType == 'symbol') { //特殊判断undefined function symbol类型
result = 'undefined'
} else if (dataType == 'string') {//字符串类型会用引号引起来
result = '"' + val + '"'
} else {
result = String(val)
}
return result
} else {
debugger
if (val == null) {
return 'null'
} else if (Object.prototype.toString.call(val) == '[object Array]') {//判断是否是数组类型
let result = []
val.forEach((item, index) => {
result[index] = imitateJSONstringfiy(item)
})
result = "'[" + result + "]'"
return (result).replace(/'/g, '"');
} else { //对象
let result = [];
if (val instanceof Number) {
val = Number(val)
result.push(val)
} else if (val instanceof String) {
val = '"' + String(val) + '"'
result.push(val)
} else if (val instanceof Boolean) {
val = Boolean(val)
result.push(val)
} else {
Object.keys(val).forEach((item, index) => {
if (typeof item != 'symbol' && val[item] !== undefined && typeof val[item] !== 'function'
&& typeof val[item] !== 'symbol') {//键或者值为这几种类型的话会被忽略
result.push('"' + item + '"' + ":" + imitateJSONstringfiy(val[item]));
}
})
return ("{" + result + "}").replace(/'/g, '"');
}
return result;
}
}
}