原生JS:JSON对象详解
JSON对象 支持到IE8,旧版的IE需要Polyfill
本文参考MDN做的详细整理,方便大家参考[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)
JSON对象本身不能被调用或者作为构造函数,除了它的这两个方法属性外 JSON 对象本身并没有什么有用的功能。
每个JSON对象,就是一个值。要么是简单类型的值,要么是复合类型的值,但是只能是一个值,不能是两个或更多的值。这就是说,每个JSON文档只能包含一个值。
描述
JSON 是一种用来序列化对象、数组、数值、字符串、布尔值和 null 的语法。它基于 JavaScript 语法,但是又有区别:一些 JavaScript 值不是 JSON,而某些 JSON 不是 JavaScript 值。参考 JSON: The JavaScript subset that isn't。
JavaScript 与 JSON 的区别
JSON对值的类型和格式有严格的规定。
- 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
- 简单类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity, -Infinity和undefined)。
- 字符串必须使用双引号表示,不能使用单引号。
- 对象的键名必须放在双引号里面。
- 数组或对象最后一个成员的后面,不能加逗号。
JavaScript类型 |
JSON与之区别 |
对象和数组 |
属性名称必须用双引号包裹;最后一个属性后面不能有逗号。 |
数值 |
前导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 异常。
- text 要解析的 JSON 字符串,可以查看 JSON 一文了解 JSON 的语法。
- reviver 可选 一个函数,用来转换解析出的属性值
- 使用 reviver 函数:
如果指定了 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 字符串中。
- value 将要序列化成 JSON 字符串的值。
- replacer 可选 如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;
如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;
如果该参数为null或者未提供,则对象所有的属性都会被序列化;
关于该参数更详细的解释和示例,请参考使用原生的 JSON 对象一文。
- space 可选 指定缩进用的空白字符串,用于美化输出(pretty-print);
如果参数是个数字,它代表有多少的空格;上限为10。改值若小于1,则意味着没有空格;
如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;
如果该参数没有提供(或者为null)将没有空格。
关于序列化,有下面五点注意事项:
- 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
- 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
- undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
- 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
- 不可枚举的属性会被忽略
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)都会被序列化。
- 如果返回一个 Number, 转换成相应的字符串被添加入JSON字符串。
- 如果返回一个 String, 该字符串作为属性值被添加入JSON。
- 如果返回一个 Boolean, "true" 或者 "false"被作为属性值被添加入JSON字符串。
- 如果返回任何其他对象,该对象递归地序列化成JSON字符串,对每个属性调用replaceer方法。除非该对象是一个函数,这种情况将不会被序列化成JSON字符串。
- 如果返回undefined,该属性值不会被宰JSON字符串中输出。
注意: 不能用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) + '"';
};
})()
};
}
原生JS:JSON对象详解的更多相关文章
- JS变量对象详解
JS变量对象详解 开年之后工作热情一直不是很高,这几天一直处于消极怠工状态.早上不想起床,起床了不想上班.明明放假之前工作热情还一直很高,一直心心念念的想把小程序项目怼出来,结果休假回来之后画风完全不 ...
- [转]json对象详解
json(javascript object notation)全称是javascript对象表示法,它是一种数据交换的文本格式,而不是一种编程语言,用于读取结构化数据.2001年由Douglas C ...
- JS DATE对象详解
1.建立时间对象:可获取年,月,日,星期,时,分,秒 var d = new Date(); console.log(d.getFullYear()+'年'+d.getMonth()+'月'+d.ge ...
- 前端高质量知识(三)-JS变量对象详解
在JavaScript中,我们肯定不可避免的需要声明变量和函数,可是JS解析器是如何找到这些变量的呢?我们还得对执行上下文有一个进一步的了解. 在上一篇文章中,我们已经知道,当调用一个函数时(激活), ...
- JS window对象详解
window 是客户端浏览器对象模型的基类,window 对象是客户端 JavaScript 的全局对象.一个 window 对象实际上就是一个独立的窗口,对于框架页面来说,浏览器窗口每个框架都包含一 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
- JS中的event 对象详解
JS中的event 对象详解 JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...
- ES6,ES2105核心功能一览,js新特性详解
ES6,ES2105核心功能一览,js新特性详解 过去几年 JavaScript 发生了很大的变化.ES6(ECMAScript 6.ES2105)是 JavaScript 语言的新标准,2015 年 ...
- Angular Npm Package.Json文件详解
Angular7 Npm Package.Json文件详解 近期时间比较充裕,正好想了解下Angular Project相关内容.于是将Npm官网上关于Package.json的官方说明文档进行了 ...
随机推荐
- 编译异常 Caused by: java.lang.UnsupportedClassVersionError:
Caused by: java.lang.UnsupportedClassVersionError: com/sumingk/platform/service/impl/ServiceSysPerso ...
- OpenCASCADE Root-Finding Algorithm
OpenCASCADE Root-Finding Algorithm eryar@163.com Abstract. A root-finding algorithm is a numerical m ...
- OpenCascade Primitives BRep-Cone
OpenCascade Primitives BRep-Cone eryar@163.com Abstract. BRep is short for Boundary Representation. ...
- SQL 数据库管理---公司培训
一.实例 一个SQL的服务引擎就是一个SQL实例,每装一次SQL就会产生一次实例. 实例分为命名实例和默认实例,一台Windows服务器可以有多个SQL实例,但是只能有一个默认实例. 不同的实例之间相 ...
- nodejs 使用fs实现多级联动
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA0gAAAEdCAIAAAC5WdDhAAAgAElEQVR4nO3da3Mc153f8X4feq5lFR
- android表白app
一.前言 马上就要520和521了,是不是还有像我一样的单身狗啊.我就知道有,所以这两天简单写了这个小程序(其实是替别人写的),虽然我并不会用去骗女孩子(因为最近太忙了,实习完之后要搞毕设,要搞论文啊 ...
- Web APi之认证(Authentication)两种实现方式后续【三】(十五)
前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不进则退,之前学的东西没怎么用,也忘记了一点,不过至少由于是切身研究,本质以及原理上的脉络 ...
- Expression Template(表达式模板,ET)
1.前言 在前一篇文章自己实现简单的string类中提到在实现+操作符重载函数时,为了防止返回时生成的临时对象调用拷贝构造函数动态申请内存空间,使用了一个叫move的函数,它是C++0x新增的特性.既 ...
- 最大值最小化(DP)
题目来源:网易有道2013年校园招聘面试一面试题 题目描述: 在印刷术发明之前,复制一本书是一个很困难的工作,工作量很大,而且需要大家的积极配合来抄写一本书,团队合作能力很重要.当时都是通过招募抄写员 ...
- css规范
1 前言 CSS 作为网页样式的描述语言,在百度一直有着广泛的应用.本文档的目标是使 CSS 代码风格保持一致,容易被理解和被维护. 虽然本文档是针对 CSS 设计的,但是在使用各种 CSS 的预编译 ...