JSON格式,(簡寫JavaScript Object Notation),是一種用於資料交換的文字格式,書寫簡單。
基於JavaScript原生語法,能夠序列化物件、陣列、數值、字串、布林值和 null。
在ES5中,增加了一個JSON物件,專門用來處理JSON格式的資料。
JSON是一個物件,但只有兩個方法:parse
和 stringify
,不能作為建構函式,也無屬性。
typeof JSON === 'object'
JSON.parse
JSON.parse()
用來解析JSON字串,得到對應的JavaScript值或物件。
JSON.parse('{}') // {}
JSON.parse('true') // true
JSON.parse('null') // null
JSON.parse 語法
JSON.parse(text[, reviver])
- text:要被解析成的字串。
如果傳入數字則會轉換成十進位制數字輸出。
如果傳入布林值則直接輸出。
如果傳入null則輸出null。
不支援其他型別的值,否則報錯。 - reviver: 可選,轉換器, 可以用來修改解析生成的原始值。
返回值: JavaScript物件/值, 對應給定JSON文字的物件/值。
reviver 引數
reviver函式,用於轉換處理解析到的JavaScript值,處理完後返回最終的結果。
轉換過程:
- 解析的值本身和它可能包含的所有屬性,按照一定遍歷順序分別呼叫reviver函式,屬性名和值作為引數兩個引數
key
和value
傳入。
遍歷順序:按照層級,從內往外遍歷,最終到達最頂層,則是解析值本身。 - reviver返回undefined,則刪除該物件,如果返回了其他值,則該值會成為當前屬性的新值。
- 當遍歷到最頂層時,因為沒有屬性了,引數key是空字串
''
,引數value則是當前解析值。
對於reviver函式的兩個引數 key
和 value
,不同的資料型別:
- 基本值型別資料(string、number、boolean)和null,以及空物件
{}
和空陣列[]
:
則key是空字串,value是對應解析值。
因為已經是最頂層,並沒有別的屬性。 - Object物件:
則key和value都存在,與屬性名和值各自對應。
最頂層會返回一個引數key為空的值。 - 陣列:
key對應陣列索引,value對應元素值。
最頂層會返回一個引數key為空的值。
基本型別的轉換:
JSON.parse('5', function (key, value) {
console.log(`key:${key}, value:${value}`)
})
// key:, value:5
JSON.parse('null', function (key, value) {
console.log(`key:${key}, value:${value}`)
})
// key:, value:null
JSON.parse('{}', function (key, value) {
console.log(`key:${key}, value:`, value)
})
// key:, value:{}
Object物件和陣列:
JSON.parse('[1, 2]', function (key, value) {
console.log(`key:${key}, value:`, value)
})
// key:0, value: 1
// key:1, value: 2
// key:, value: (2) [empty × 2]
JSON.parse('{ "user": "張三", "info": { "age": 25, "sex": 1 } }', function (key, value) {
console.log(`key:${key}, value::`, value)
})
// key:user, value:: 張三
// key:age, value:: 25
// key:sex, value:: 1
// key:info, value:: {}
// key:, value:: {}
資料處理:
JSON.parse('[1, 2]', function (key, value) {
if(key === '') {
return value
}
return value + 3
})
// [4, 5]
JSON.parse 特性
在解析JSON字串的時候,需要注意到JSON格式的一些規範,不然就容易報錯。
JSON資料對值的型別和格式,都有嚴格的規定,具體的規則如下:
- 該方法使用字串型別JSON格式資料。
該方法也支援數字、布林值和null三個型別的值,轉換出對應的字面值。
不支援其他型別。
JSON.parse('"中國"')
// '中國'
JSON.parse(null) // null
JSON.parse(111.) // 111
JSON.parse(0x12) // 18
JSON.parse(true) // true
JSON.parse([])
// Uncaught SyntaxError: Unexpected end of JSON input
- 字串必須使用雙引號,不能使用單引號。
JSON.parse('"String"')
// 'String'
JSON.parse('\'String\'')
// Uncaught SyntaxError: Unexpected token ' in JSON at position 0
- 只支援十進位制的字串,但小數點後必須跟上數字。
JSON.parse('111') // 111
JSON.parse('0x12')
// Uncaught SyntaxError: Unexpected token x in JSON at position 1
JSON.parse('111.232') // 111.232
JSON.parse('111.')
// Uncaught SyntaxError: Unexpected end of JSON input
- 不能使用undefined、Symbol和BigInt,數字也不支援NaN、Infinity和-Infinity,都會報錯。
JSON.parse(undefined)
// Uncaught SyntaxError: Unexpected token u in JSON at position 0
JSON.parse(Symbol())
// Uncaught TypeError: Cannot convert a Symbol value to a string
JSON.parse('12n')
// Uncaught SyntaxError: Unexpected token n in JSON at position 2
- 複合型別,只能是:
[]
和{}
這樣的字面量。
不能使用物件建構函式,因為會當作執行語句,不支援。
不能使用Object和Array,也不能是函式、RegExp物件、Date物件、Error物件等。
JSON.parse('[]')
// []
JSON.parse('Object()')
// Uncaught SyntaxError: Unexpected token O in JSON at position 0
- 物件的屬性名必須使用雙引號。
JSON.parse('{"key": 1 }')
// {key: 1}
JSON.parse('{key: 1 }')
// Uncaught SyntaxError: Unexpected token k in JSON at position 1
- 陣列或物件最後一個成員的後面,不能加逗號。
JSON.parse('[1, 2, 3, 4, ]')
// VM2771:1 Uncaught SyntaxError: Unexpected token ] in JSON at position 13
JSON.parse('{"key" : 1, }')
// VM2779:1 Uncaught SyntaxError: Unexpected token } in JSON at position 12
- 支援unicode轉義。
JSON.parse('{"\u0066":333}')
// {f: 333}
- 部分控制字元、轉義字元不支援,如'\n'、'\t'等。
JSON.parse('"\n"')
// Uncaught SyntaxError: Unexpected token
解析的其他方法
將json字串轉成json物件(js物件值),還可以使用其他方法,但是非安全程式碼。
const str = '{"name":"json","age":18}'
const json = JSON.parse(str)
const json = eval("(" + str + ")")
const json = (new Function("return " + str))()
JSON.stringify
JSON.stringify()
將一個JavaScript物件或值轉換為JSON格式字串。
JSON.stringify 語法
JSON.stringify(value[, replacer [, space]])
- value:將要序列化成 一個 JSON 字串的JavaScript物件或值。
- replacer 可選,用於處理將要序列化的值。
- space 可選,指定縮排用的空白字串,用於美化輸出。
返回值: 一個表示給定值的JSON格式字串。
replacer引數
replacer 引數可以以下三種情況:
- 如果是null、undefined或其他型別,則被忽略,不做處理;
JSON.stringify({key: 'json'}, null, null) // '{"key":"json"}'
JSON.stringify({key: 'json'}, true) // '{"key":"json"}'
- 如果是一個陣列,則只有包含在這個陣列中的屬性名,才會最終被序列化到結果字串中;
只對物件的屬性有效,對陣列無效。
const obj = {
json: 'JSON',
parse: 'PARSE',
stringify: 'STRINGIFY'
}
JSON.stringify(obj, ['parse', 'stringify'])
// '{"parse":"PARSE","stringify":"STRINGIFY"}'
- 如果是一個函式,被序列化的值的每個屬性都會經過該函式的轉換和處理;
處理過程:
- 函式有兩個引數,屬性名(key)和屬性值(value),都會被序列化;
- 第一次呼叫時,key為空字串,value則為需要序列化的整個物件;
- 第二次處理時,會把第一次的的結果傳過來,後續的每一次的處理都將接收上一次處理的結果;
- 後面,將依次處理每個屬性名和屬性值,完成後返回。
JSON.stringify({ json: 1, stringify: { val: 'rr'} }, (key, value) => {
console.log(`key:${key},value:`, value)
return value
})
// key:,value: {json: 1, stringify: {…}}
// key:json,value: 1
// key:stringify,value: {val: 'rr'}
// key:val,value: rr
// '{"json":1,"stringify":{"val":"rr"}}'
value的型別處理:
- 如果返回基本型別字串、數字、布林值、null,則直接被新增到序列化後的JSON字串中;
- 如果返回其他物件,則會在後續依次序列化該物件的屬性,如果是函式則不作處理;
- 如果返回或undefined,則不會輸出該屬性。
- 序列化陣列時,如果value返回undefined或者一個函式,將會被null取代。
JSON.stringify({ json: 1, stringify: 'rr' }, (key, value) => {
if (typeof value === 'number') {
return 'ss'
}
return value
})
// '{"json":"ss","stringify":"rr"}'
JSON.stringify({ json: 1, stringify: 'rr' }, (key, value) => {
if (typeof value === 'number') {
value = undefined
}
return value
})
// '{"stringify":"rr"}'
下面示例,是返回物件值時的處理:
JSON.stringify({ json: 1, stringify: 'rr' }, (key, value) => {
if (typeof value === 'object') { // 第一次返回整個物件時,型別是object
return { parse: 'dd' }
}
return value
})
'{"parse":"dd"}'
space 引數
space 引數用來控制結果字串裡面的間距,美化輸出。可以輸入的值有以下三種情況:
- 如果是一個數字, 序列化時,每一層級比上一層級多縮排對應數字值的空格,範圍在 1 - 10,即最小1個最大10個空格;
- 如果是一個字串,序列化時,該字串會新增在每行前面,每一層級比上一層級多縮排該字串,最多是個字元,超過則擷取字串;
- 如果是null、undefined或其他型別,則被忽略,不做處理。
JSON.stringify({key: 'json'}, null, 2)
// '{\n "key": "json"\n}'
JSON.stringify({key: 'json', list: { str: 'str' } }, null, '|-')
// '{\n|-"key": "json",\n|-"list": {\n|-|-"str": "str"\n|-}\n}'
JSON.stringify({key: 'json'}, null, null)
// '{"key":"json"}'
JSON.stringify 特性
- 基本型別值字串、數字、布林值,以及String、Boolean、Number物件值,都會轉成原始值字串輸出。
JSON.stringify(333) // '333'
JSON.stringify(true) // 'true'
JSON.stringify(new String('333')) //'"333"'
JSON.stringify(Boolean(true)) // 'true'
- 基本型別的字串,轉換結果會帶雙引號。
因為在還原時,雙引號會讓JavaScript知道是字串,而不是變數。
JSON.stringify('json') === 'json' // false
JSON.stringify('json') === '"json"' // true
- undefined、函式、symbol以及XML物件:
- 出現在Object物件中時,會被忽略;
- 出現在陣列中時,會被序列化成null;
- 單獨出現時,會返回undefined。
JSON.stringify(Symbol()) // undefined
JSON.stringify([Symbol(), Math.abs, undefined]) // '[null,null,null]'
JSON.stringify({ [Symbol()]: Math.abs, key: undefined }) // '{}'
- NaN、Infinity和-Infinity等值,還有null,都會被序列化成null。
JSON.stringify(null) // 'null'
JSON.stringify(NaN) // 'null'
- Object物件,以及
Map/Set/WeakMap/WeakSet
等複合型別物件,序列化時會忽略物件的不可遍歷屬性。
const obj = {}
Object.defineProperties(obj, {
'json': { value: 'JSON', enumerable: true },
'stringify': { value: 'STRINGIFY', enumerable: false }
})
JSON.stringify(obj)
// '{"json":"JSON"}'
- 以symbol為屬性名的屬性將被忽略。
JSON.stringify({[Symbol()]: 333}) // '{}'
- 除了陣列,其他物件的屬性在序列化時,順序可能會亂。
const a = { '1': 911, 'r': 822, '11': 9922}
JSON.stringify(a)
// '{"1":911,"11":9922,"r":822}'
- 轉換的物件如果定義了
toJSON()
方法,則該方法的返回值就是轉換物件的序列化結果。
該過程會忽略其他屬性。
const a = { key: 'json' }
a.toJSON = () => 'JSON'
JSON.stringify(a)
// '"JSON"'
- RegExp物件、Error物件都會序列化為空物件字串。
JSON.stringify(/\d/) // "{}"
JSON.stringify(new Error()) // "{}"
想要序列化相應物件,需要設定實現toJSON方法才行。
RegExp.prototype.toJSON = RegExp.prototype.toString
JSON.stringify(/\d/) // '"/\\\\d/"'
- Date物件已經定義了toJSON(),並將其轉換為string字串,因此可被序列化。
同Date.toISOString()
。
JSON.stringify(new Date())
// '"2021-12-31T02:24:05.477Z"'
- 迴圈引用的物件執行此方法,會丟擲錯誤。
物件之間相互引用,形成無限迴圈。
const a = {}
a.key = a
JSON.stringify(a)
// Uncaught TypeError: Converting circular structure to JSON
- 轉換BigInt型別的值會丟擲TypeError錯誤。
BigInt值不能JSON序列化
JSON.stringify(12n)
// Uncaught TypeError: Do not know how to serialize a BigInt
- 更好的支援unicode轉義符
const a = {'\u0066': 333}
JSON.stringify(a)
// '{"f":333}'