其实在前端开发过程中,经常会用到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)被允许 ; 字符串必须用双引号括起来。请参考下面的示例,可以看到 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。
网友评论文明上网理性发言 已有0人参与
发表评论: