其实在前端开发过程中,经常会用到JavaScript和JSON,对于二者它们之间的关系,您能说清楚吗?接下来一起了解下吧。
JSON对象包含两个方法: 用于解析 JavaScript Object Notation (JSON) 的 parse() 方法,以及将对象/值转换为 JSON字符串的 stringify() 方法。除了这两个方法, JSON这个对象本身并没有其他作用,也不能被调用或者作为构造函数调用。
描述
JavaScript Object Notation
JSON 是一种语法,用来序列化对象、数组、数值、字符串、布尔值和 null 。它基于 JavaScript 语法,但与之不同:JavaScript不是JSON,JSON也不是JavaScript。
误解:JSON并不是JavaScript 的子集?
这些年来,我们一遍又一遍地听到它:" JSON是JavaScript的子集"。你猜怎么了?他们错了。错,错,错。您会发现,在细节中,并且没有避免的方法:并非所有JSON格式的文本都是合法的JavaScript代码:
{"JSON":"ro
cks!"}
复制上面的确切代码,然后将其粘贴到Firebug或Web Inspector中的一对括号内(避免在JavaScript语法中产生歧义):
等一下 SyntaxError: Unexpected token ILLEGAL?那没有任何意义!这只是一个普通的对象文本,怎么能说是一个SyntaxError?
在适当的JSON解析器中尝试相同的代码。完全没有问题。
当然,这不只是常规对象文字。里面也有一个偷偷摸摸的小Unicode字符:就在" ro"和" cks!"之间。有一个很小的U + 2028。您的浏览器可能不会显示它,因为它是空格:LINE SEPARATOR,但它仍然存在。如果将字符替换为U + 2029(PARAGRAPH SEPARATOR),则会出现完全相同的问题。
JSON + U + 2028 =☺
根据JSON规范,您可以在任何字符串中安全地使用此字符。它不是引号,也不是反斜杠,也不是控制字符。这只是一个奇怪的Unicode空格字符:
JavaScript + U + 2028 =☹
另一方面,ECMA-262(JavaScript基于的标准)对字符串的定义略有不同:根据7.8.4字符串文字,字符串可以包含任何内容,只要它不是引号,反斜杠或行终止符即可:
oubleStringCharacter ::
SourceCharacter but not double-quote " or backslash \ or LineTerminator
\ EscapeSequence
SingleStringCharacter ::
SourceCharacter but not single-quote ' or backslash \ or LineTerminator
\ EscapeSequence
什么是行终止符?让我们看一下!
以下字符被认为是行终止符:
-
\u000A -换行
-
\u000D -回车
-
\u2028 -分线器
-
\u2029 -段落分隔符
JavaScript中的任何字符串都不能包含文字U + 2028或U + 2029。
由于这两个不可见的Unicode字符,JSON 并不是 JavaScript的子集。
在大多数应用程序中,您不会注意到此问题。首先,行分隔符和段落分隔符没有被广泛使用。其次,任何适当的 JSON解析器在解析时都不会出现问题。
但是,当您使用JSONP处理时,就无法解决:您被迫在浏览器中使用JavaScript解析器。而且,如果您要发送别人输入的数据,那么一个很小的U + 2028或U + 2029可能会潜入并破坏您漂亮的跨域API。
解决方案
幸运的是,解决方案很简单:如果我们查看JSON规范,就会发现U + 2028或U + 2029可能出现的唯一位置是字符串。因此\u2028,\u2029只要需要发送一些JSONP,我们就可以简单地将每个U + 2028替换为(转义序列),并将U + 2029替换为。
它已经在Rack :: JSONP中修复,我鼓励所有发送JSONP的框架或库都执行相同的操作。这是大多数语言的单行修补程序,结果仍然是100%有效的JSON。
JavaScript 与 JSON 的区别
| JavaScript类型 | JSON 的不同点 |
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 对象和数组 | 属性名称必须是双引号括起来的字符串;最后一个属性后不能有逗号。 |
| 数值 | 禁止出现前导零( JSON.stringify 方法自动忽略前导零,而在 JSON.parse 方法中将会抛出 SyntaxError);如果有小数点, 则后面至少跟着一位数字。 |
| 字符串 | 只有有限的一些字符可能会被转义;禁止某些控制字符; Unicode 行分隔符 (U+2028)和段分隔符 (U+2029)被允许 ; 字符串必须用双引号括起来。请参考下面的示例,可以看到 JSON.parse()
能够正常解析,但将其当作JavaScript解析时会抛出 SyntaxError
错误: let code = '"\u2028\u2029"';JSON.parse(code); // 正常eval(code); // 错误
|
完整的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
在JSONNumber(数字内部不允许包含空格)或JSONString(字符串内部的空格被解释为相应的字符,否则就有问题了)之外的任何位置可以有多余的空白字符。JSON只支持这些空白字符: 制表符(U+0009),回车(U+000D),换行(U+000A)以及空格(U+0020)。
方法
JSON有两种方法:JSON.parse()和JSON.stringify()
JSON.parse()
解析JSON字符串并返回对应的值,可以额外传入一个转换函数,用来将生成的值和其属性, 在返回之前进行某些修改。
JSON.stringify()
返回与指定值对应的JSON字符串,可以通过额外的参数, 控制仅包含某些属性, 或者以自定义方法来替换某些key对应的属性值。
Polyfill
JSON对象可能不被老版本的浏览器支持。可以将下面的代码放到JS脚本最开始的位置,这样就可以在没有原生支持 JSON 对象的浏览器(如IE6)中使用 JSON对象。
以下算法是对原生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) + '"';
};
})()
};
}
业界更专业, 更强大的JSON对象 polyfills 是 JSON2 和 JSON3。