JavaScript Object Notation 与(JSON) 的 区别

针对于这两点,我们举个例子,对于对象和数组类型:

// 属性名称必须是双引号括起来的字符串

const test1 = "['1','1']"

JSON.parse(test1) // Uncaught SyntaxError: Unexpected token ' in JSON at position 1

const test2 = "{'name':'gating'}"

JSON.parse(test2) // Uncaught SyntaxError: Unexpected token o in JSON at position 1

const test3 = '["2","1"]'

JSON.parse(test3) // ["2","1"]

const test4 = '{"name":"gating"}'

JSON.parse(test3) // {name: "gating"}

// 最后一个属性后不能有逗号

const test5 = '["2","1",]'

JSON.parse(test5) // Uncaught SyntaxError: Unexpected token ] in JSON at position 9

const test6 = '{"name":"gating",}'

JSON.parse(test6) // Uncaught SyntaxError: Unexpected token } in JSON at position

17

对于数值类型:

// 禁止出现前导零

const test7 = [00010, 1]

JSON.stringify(test7) // "[8,1]"

const test8 = "[00010, 1]"

JSON.parse(test8) // SyntaxError: Unexpected number in JSON at position 2**

// 如果有小数点,则后面至少跟着一位数字。

const test9 = [1, 1.]

JSON.stringify(test9) // "[1,1]"

const test10 = "[1, 1.]"

JSON.parse(test10) // Uncaught SyntaxError: Unexpected token ] in JSON at position

6

ps: 0+数字表示8进制,- -所以上面打印出来的是8,同样的有:0b+数字(二进制)、0x+数字

(16进制),其实0o+数字也可以表示8进制

其实还有一个字符串类型,JavaScript和JSON处理是不一致的,这里为啥我只写两点呢?是因

为还有现在在新版的Chrome已经可以解析正常,但是想具体可以查看下面参考链接自行了解,

这里就不展开了

参考:JavaScript 与 JSON 的区别,字符串那一点我在Chrome 85.0.4183.83以及可以正常解

stringify() 方法用于将JavaScript值转换为JSON字符串。

虽然我们经常用这个方法,但我想估计有不少人不知道它居然有三个参数之多吧?分别是value

、replacer、space。

JSON.stringify(value[, replacer [, space]])

value

将要序列化成 一个 JSON 字符串的值。

replacer 可选

如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换

和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的

JSON 字符串中;如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。

space 可选

指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多

少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(当字符串长度

超过10个字母,取其前10个字母),该字符串将被作为空格;如果该参数没有提供(或者为

null),将没有空格。

通常我们最常用的就是第一个参数,也就是value参数,但是你知道它的运算规则是怎么样的吗

?闲话不多说,直接上例子

NaN 和 Infinity 格式的数值及 null 都会被当做 null

JSON.stringify([NaN, Infinity, null]) // [null,null,null]

undefined、任意的函数以及 symbol 值的处理

出现在非数组对象的属性值中时,在序列化过程中会被忽略

JSON.stringify({x: undefined, y: Object, z: Symbol("")}) // "{}"

出现在数组中时被转换成null

JSON.stringify([undefined, Object, Symbol("")])  // "[null,null,null]"

单独出现则会返回undefined

JSON.stringify(undefined)  // undefined

JSON.stringify(Object)  // undefined

JSON.stringify(Symbol(""))  // undefined

所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它

们。

JSON.stringify({[Symbol("foo")]: "foo"}) // "{}"

JSON.stringify({[Symbol.for("foo")]: "foo"}, [Symbol.for("foo")]) // "{}"

转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。

JSON.stringify({

  toJSON: function() {

    return 'gating'

  }

}) // "gating"

const name = {

  age: 18,

  toJSON: function () {

    return 'gating'

  },

}

JSON.stringify({ name }) // {"name":"gating"}

又因为Date对象上挂载了一个toJSON方法,所以针对于Date类型,它默认就会调用Date类型上

的toJSON方法(同Date.toISOString())

JSON.stringify(new Date("2020/01/01")) // "2019-12-31T16:00:00.000Z" 因为中国在东八

区,所以相差了8小时

ps: 东八区(UTC/GMT+08:00)是比世界协调时间(UTC)/格林尼治时间(GMT)快8小时的时区

其他类型的对象,仅会序列化对象可枚举的属性,包括 Map/Set/WeakMap/WeakSet

JSON.stringify(

  Object.create(null, {

    x: { value: 'x'}, // enumerable 默认为不可枚举

    y: { value: 'y', enumerable: true },

  })

) // "{"y":"y"}"

const map = new Map()

Object.defineProperty(map, 'name', {

  value: 'gating',

  enumerable: true

})

Object.defineProperty(map, 'age', {

  value: 18

})

JSON.stringify(map) // {"name":"gating"}

JSON.stringify(new Set) // {}

JSON.stringify(new RegExp) // {}

看到这里,你基本已经知道运算规则是怎么样滴了,也就知道了为什么JSON.stringify +

JSON.parse不能转换函数、正则、Error等对象了吧?

那么接下来就要了解下更有意思的东西啦,就是stringify第二个参数replacer啦

replacer 参数可以用来来更改默认的字符串化的行为。它可以是一个函数或者一个数组。如果

该参数为 null 或者未提供,则对象所有的属性都会被序列化。

作为函数

在开始时, replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个

对象。随后每个对象或数组上的属性会被依次传入。

这句话看不太懂?不要紧,举个例子你就懂了

function replacer(key, value) {

  console.log('[' + key + ']:' + value)

  return value

}

JSON.stringify({ name: 'gating', age: 18 }, replacer)

// []:[object Object]

// [name]:gating

// [age]:18

上面例子中,他会执行三次,也就是一开始他会默认传一个空字符串作为键,而键值是整个对

象;第二次键为name,键值为gating,以此类推。

当然,这里也有个特别需要注意的点,就是返回的是一个对象的时候,该对象递归地序列化成

JSON 字符串,对每个属性调用replacer方法。除非该对象是一个函数,这种情况将不会被序列

化成 JSON 字符串。

比如:

function replacer(key, value) {

  return {a:1}

}

JSON.stringify({}, replacer)

因为我们每次返回的都是对象,那么每次都会调用replacer,所以会造成堆栈溢出,那么我们

举个不会溢出的小栗子例子吧🤣:

function replacer(key, value) {

  if(typeof value === 'object'){

    return { age: 9 }

  }

  return value * 2

}

const name = {}

JSON.stringify(name, replacer) // {"age":18}

在这里,每一次处理的对象,都是前一次返回的值。因为我们replacer修改了name对象,接着

就要递归replacer处理修改后的对象。

总结:递归处理中,每一次处理的对象,都是前一次返回的值。

function f(key, value){

  console.log(value)

  if (typeof value === "object"){

    return {b: 2};

  }

  return value*2;

}

JSON.stringify(o,f)

那么,既然是更改默认的字符串化的行为,那么我就尝试下更改下吧

replacer——数字Double

function replacer(key, value) {

  if (typeof value === "number") {

    return value * 2;

  }

  return value;

}

const me = {

  name: 'gating',

  age: 9,

}

JSON.stringify(me, replacer) // {"name":"gating","age":18}

replacer——剔除不要的属性

function replacer(key, value) {

  if (typeof value === "string") {

    return undefined;

  }

  return value;

}

const me = {

  name: 'gating',

  age: 18,

}

JSON.stringify(me, replacer) // {"age":18} 剔除了name属性

JSON.stringify([1,"2"], replacer) // "[1,null]"

注意: 不能用 replacer 方法,从数组中移除值(values),如若返回 undefined 或者一个函

数,将会被 null 取代(其实从 value 的运算规则我们也知道会出现这个结果了)。

作为数组

数组的值代表将被序列化成JSON字符串的属性名

const me = {

  name: 'gating',

  age: 18,

}

JSON.stringify(me, ['name']) // {"name":"gating"} 只保留了name的属性值

JSON.stringify(['a', 'b'], ['0']) // ['a', 'b']

这个类似白名单的数组,只对对象的属性有效,对数组无效。

space 参数用来控制结果字符串里面的间距,增加返回的 JSON 字符串的可读性。如果是一个

数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格);如

果是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。

使用数字

JSON.stringify({ name: "gating", age: 18 }, null, 6)

/*

"{

      "name": "gating",

      "age": 18

}"

*/

使用字符串

JSON.stringify({ name: "gating", age: 18 }, null, '|-')

/*

"{

|-"name": "gating",

|-"age": 18

}"

*/

使用制表符(\t)来缩进

因为最用用到要美化JSON的场景,所以顺便把制表符也写出来了 😊

就是提交的时候是json,返回的时候美化json显示到输入框内

JSON.stringify({ name: "gating", age: 18 }, null, '\t')

/*

"{

"name": "gating",

"age": 18

}"

*/

深圳网站建设www.sz886.com

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343