JSON對象 支持到IE8,舊版的IE須要Polyfilljavascript
本文參考MDN作的詳細整理,方便你們參考[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)java
JSON對象自己不能被調用或者做爲構造函數,除了它的這兩個方法屬性外 JSON 對象自己並無什麼有用的功能。git
每一個JSON對象,就是一個值。要麼是簡單類型的值,要麼是複合類型的值,可是隻能是一個值,不能是兩個或更多的值。這就是說,每一個JSON文檔只能包含一個值。github
描述正則表達式
JSON 是一種用來序列化對象、數組、數值、字符串、布爾值和 null 的語法。它基於 JavaScript 語法,可是又有區別:一些 JavaScript 值不是 JSON,而某些 JSON 不是 JavaScript 值。參考 JSON: The JavaScript subset that isn't。算法
JavaScript 與 JSON 的區別json
JSON對值的類型和格式有嚴格的規定。數組
JavaScript類型瀏覽器 |
JSON與之區別session |
對象和數組 |
屬性名稱必須用雙引號包裹;最後一個屬性後面不能有逗號。 |
數值 |
前導0不能使用(在 JSON.stringify 中將會被忽略,在 JSON.parse 會拋出錯誤);小數點後面至少有一個數字。 |
字符串 |
只有有限的字符可以被轉義;不容許某些控制字符;但容許使用Unicode 行分隔符 (U+2028) 和段落分隔符 (U+2029) ; 字符串必須用雙引號括起來。 在 Javascript 中,下面的示例中 JSON.parse() 可以正常解析但 SyntaxError 會出錯: var code = '"\u2028\u2029"'; JSON.parse(code); // works fine eval(code); // fails
|
完整的JSON語法以下:
JSON = null
or true or false
or JSONNumber
or JSONString
or JSONObject
or JSONArray
JSONNumber = - PositiveNumber
or PositiveNumber
PositiveNumber = DecimalNumber
or DecimalNumber . Digits
or DecimalNumber . Digits ExponentPart
or DecimalNumber ExponentPart
DecimalNumber = 0
or OneToNine Digits
ExponentPart = e Exponent
or E Exponent
Exponent = Digits
or + Digits
or - Digits
Digits = Digit
or Digits Digit
Digit = 0 through 9
OneToNine = 1 through 9
JSONString = ""
or " StringCharacters "
StringCharacters = StringCharacter
or StringCharacters StringCharacter
StringCharacter = any character
except " or \\ or U+0000 through U+001F
or EscapeSequence
EscapeSequence = \\" or \\/ or \\\\ or \\b or \\f or \\n or \\r or \\t
or \\u HexDigit HexDigit HexDigit HexDigit
HexDigit = 0 through 9
or A through F
or a through f
JSONObject = { }
or { Members }
Members = JSONString : JSON
or Members , JSONString : JSON
JSONArray = [ ]
or [ ArrayElements ]
ArrayElements = JSON
or ArrayElements , JSON
空白字符能夠出如今任意位置,可是數值類型的數字中間不能有空白字符,字符串中間不能隨意添加空白字符,由於添加的空白字符會被解釋爲相應的字符值,從而引發錯誤。有效空白字符只包括製表符 (U+0009)、回車符 (U+000D)、換行符 (U+000A) 和空格 (U+0020) 。
方法
JSON.parse(text[, reviver])
解析JSON字符串text, 能夠選擇改變前面解析後的值及其屬性,而後返回解析的值。它從 text 字符串解析出的一個 Object。若是被解析的 JSON 字符串包含語法錯誤,則會拋出 SyntaxError 異常。
若是指定了 reviver 函數,則解析出的 JavaScript 值(解析值)會通過一次轉換後纔將被最終返回(返回值)。更具體點講就是:解析值自己以及它所包含的全部屬性,會按照必定的順序(從最最裏層的屬性開始,一級級往外,最終到達頂層,也就是解析值自己)分別的去調用 reviver 函數,在調用過程當中,當前屬性所屬的對象會做爲 this 值,當前屬性名和屬性值會分別做爲第一個和第二個參數傳入 reviver 中。若是 reviver 返回 undefined,則當前屬性會從所屬對象中刪除,若是返回了其餘值,則返回的值會成爲當前屬性新的屬性值。
當遍歷到最頂層的值(解析值)時,傳入 reviver 函數的參數會是空字符串 ""(由於此時已經沒有真正的屬性)和當前的解析值(有可能已經被修改過了),當前的 this 值會是 {"": 修改過的解析值},在編寫 reviver 函數時,要注意到這個特例。(譯者按:這個函數的遍歷順序按深度優先遍歷)
JSON.parse('{"p": 5}', function (key, value) {
if(key === '') return value; // 若是到了最頂層,則直接返回屬性值,
return value* 2; // 不然將屬性值變爲原來的 2 倍。
}); // { p: 10 }
JSON.parse('{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}', function (k, v) {
console.log(k); // 輸出當前的屬性名,從而得知遍歷順序是從內向外的,
// 最後一個屬性名會是個空字符串。
return v; // 返回原始屬性值,至關於沒有傳遞 reviver 參數。
});
// 1
// 2
// 4
// 6
// 5
// 3// ""
JSON.stringify(value[, replacer [, space]])
將任意的 JavaScript 值序列化成 JSON 字符串。若轉換的函數被指定,則被序列化的值的每一個屬性都會通過該函數的轉換和處理;若轉換的數組被指定,只有包含在這個數組中的屬性名纔會被序列化到最終的 JSON 字符串中。
若是該參數是一個數組,則只有包含在這個數組中的屬性名纔會被序列化到最終的 JSON 字符串中;
若是該參數爲null或者未提供,則對象全部的屬性都會被序列化;
關於該參數更詳細的解釋和示例,請參考使用原生的 JSON 對象一文。
若是參數是個數字,它表明有多少的空格;上限爲10。改值若小於1,則意味着沒有空格;
若是該參數爲字符串(字符串的前十個字母),該字符串將被做爲空格;
若是該參數沒有提供(或者爲null)將沒有空格。
關於序列化,有下面五點注意事項:
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({x: 5, y: 6});
// '{"x":5,"y":6}' 或者 '{"y":6,"x":5}' 均可能
JSON.stringify([new Number(1), new String("false"), new Boolean(false)]);
// '[1,"false",false]'
JSON.stringify({x: undefined, y: Object, z: Symbol("")});
// '{}'
JSON.stringify([undefined, Object, Symbol("")]);
// '[null,null,null]'
JSON.stringify({[Symbol("foo")]: "foo"});
// '{}'
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";
}
});
// '{}'
// 不可枚舉的屬性默認會被忽略:
JSON.stringify( Object.create(null, { x: { value: 'x', enumerable: false }, y: { value: 'y', enumerable: true } }) );
// '{"y":"y"}'
replacer參數
replacer參數能夠是一個函數或者一個數組。做爲函數,它有兩個參數,鍵(key)值(value)都會被序列化。
注意: 不能用replacer方法,從數組中移除值(values),如若返回undefined或者一個函數,將會被null取代。
例子1(function)
function replacer(key, value) {
if (typeof value === "string") {
return undefined;
}
return value;
}
var foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
var jsonString = JSON.stringify(foo, replacer);
JSON序列化結果爲 {"week":45,"month":7}.
例子2(array)
若是replacer是一個數組,數組的值表明將被序列化成JSON字符串的屬性名。
JSON.stringify(foo, ['week', 'month']);
// '{"week":45,"month":7}', 只保留「week」和「month」屬性值。
space 參數
space 參數用來控制結果字符串裏面的間距。若是是一個數字, 則在字符串化時每一級別會比上一級別縮進多這個數字值的空格(最多10個空格);若是是一個字符串,則每一級別會比上一級別多縮進用該字符串(或該字符串的前十個字符)。
JSON.stringify({ a: 2 }, null, " "); // '{\n "a": 2\n}'
使用製表符(\t)來縮進:
JSON.stringify({ uno: 1, dos : 2 }, null, '\t')
// '{ \
// "uno": 1, \
// "dos": 2 \
// }'
toJSON 方法
若是一個被序列化的對象擁有 toJSON 方法,那麼該 toJSON 方法就會覆蓋該對象默認的序列化行爲:不是那個對象被序列化,而是調用 toJSON 方法後的返回值會被序列化,例如:
var obj = {
foo: 'foo',
toJSON: function () {
return 'bar';
}
};
JSON.stringify(obj); // '"bar"'
JSON.stringify({x: obj}); // '{"x":"bar"}'
JSON.stringify用做 JavaScript
注意JSON不是javascript嚴格意義上的子集,在JSON中不須要省略兩條終線(Line separator和Paragraph separator)但在JavaScript中須要被省略。所以,若是JSON被用做JSONP時,下面方法可使用:
function jsFriendlyJSONStringify (s) {
return JSON.stringify(s).
replace(/\u2028/g, '\\u2028').
replace(/\u2029/g, '\\u2029');
}
var s = {
a: String.fromCharCode(0x2028),
b: String.fromCharCode(0x2029)
};
try {
eval('(' + JSON.stringify(s) + ')');
} catch (e) {
console.log(e); // "SyntaxError: unterminated string literal"
}
// No need for a catch
eval('(' + jsFriendlyJSONStringify(s) + ')');
// console.log in Firefox unescapes the Unicode if
// logged to console, so we use alert
alert(jsFriendlyJSONStringify(s)); // {"a":"\u2028","b":"\u2029"}
使用 JSON.stringify 結合 localStorage 的例子
一些時候,你想存儲用戶建立的一個對象,而且,即便在瀏覽器被關閉後仍能恢復該對象。下面的例子是 JSON.stringify 適用於這種情形的一個樣板:
// 建立一個示例數據
var session = {
'screens' : [],
'state' : true
};
session.screens.push({"name":"screenA", "width":450, "height":250});
session.screens.push({"name":"screenB", "width":650, "height":350});
session.screens.push({"name":"screenC", "width":750, "height":120});
session.screens.push({"name":"screenD", "width":250, "height":60});
session.screens.push({"name":"screenE", "width":390, "height":120});
session.screens.push({"name":"screenF", "width":1240, "height":650});
// 使用 JSON.stringify 轉換爲 JSON 字符串
// 而後使用 localStorage 保存在 session 名稱裏
localStorage.setItem('session', JSON.stringify(session));
// 而後是如何轉換經過 JSON.stringify 生成的字符串,該字符串以 JSON 格式保存在 localStorage 裏
var restoredSession = JSON.parse(localStorage.getItem('session'));
// 如今 restoredSession 包含了保存在 localStorage 裏的對象
console.log(restoredSession);
Polyfill
JSON 對象不被舊版本瀏覽器支持。你能夠把下面代碼放到腳本的開始位置,這樣就能夠在那些沒有原生支持 JSON 對象的瀏覽器(好比IE6)中使用 JSON 對象。關於 JSON 對象更復雜且有名的 polyfills 是 JSON2 和 JSON3。
下面的算法用來模擬原生 JSON 對象:
if (!window.JSON) {
window.JSON = {
parse: function(sJSON) { return eval('(' + sJSON + ')'); },
stringify: (function () {
var toString = Object.prototype.toString;
var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'};
var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;
return function stringify(value) {
if (value == null) {
return 'null';
} else if (typeof value === 'number') {
return isFinite(value) ? value.toString() : 'null';
} else if (typeof value === 'boolean') {
return value.toString();
} else if (typeof value === 'object') {
if (typeof value.toJSON === 'function') {
return stringify(value.toJSON());
} else if (isArray(value)) {
var res = '[';
for (var i = 0; i < value.length; i++)
res += (i ? ', ' : '') + stringify(value[i]);
return res + ']';
} else if (toString.call(value) === '[object Object]') {
var tmp = [];
for (var k in value) {
if (value.hasOwnProperty(k))
tmp.push(stringify(k) + ': ' + stringify(value[k]));
}
return '{' + tmp.join(', ') + '}';
}
}
return '"' + value.toString().replace(escRE, escFunc) + '"';
};
})()
};
}