某天,女朋友问我关于 JSON 的问题,虽然心里清楚,但却表述不清,她不理解,这有说明自己对 JSON 还没有透彻的理解,于是就有了这篇文章。
虽然 JSON 都知道了,但不妨再介绍一下。
1、JSON 简介
JSON ,全称是 JavaScript Object Notation,即 JavaScrip 对象标记法。这是一种轻量级(Light-Weight)、基于文本的(Text-Based)、可读的(Human-Readable)格式。
1.1 JSON 的语法规则
- 数组(Array)用方括号(“[]”)表示。
- 对象(Object)用大括号(”{}”)表示。
- 名称/值对(name/value)之间用冒号(”:”)隔开。
- 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组。
- 并列的数据之间用逗号(“,”)分隔
- 数组或对象的每个成员的值,可以是简单值,也可以是复合值
2、JSON 在 JavaScript 和 PHP 中
首先弄清楚的一点是 JSON 的表示
在 JavaScript 中 JSON 有如下表示形式:
var jsonArr = [{"name":"lucy","age":18},{"name":"lala","age":17}]; // JSON 数组
var jsonObj = {"name":"lucy","age":18}; // JSON 对象
var jsonStr = '{"name":"lucy","age":18}'; // 符合 JSON 格式的字符串
在 PHP 中 JSON 就只有如下表示了:
$jsonStr = '{"name":"lucy","age":18}'; // 符合 JSON 格式的字符串
之所以由上述差异,最大原因还是因为 JavaScript 支持 对象/数组 字面量,而 PHP 不支持。
所以说,从 PHP 返回 JSON数据到前端,实际上就是返回符合 JSON 格式的字符串!
下面以 ajax 请求 JSON 数据为例说一下。
假定有 index3.php ,向前端返回 JSON 字符串,如下图:
假定有 index4.html 向 index3.php 发 ajax 请求,如下图。
显然 js 中得到的只是符合 JSON 格式的字符串,所以无法通过 data.a 以对象的形式访问。
这就要提到 JSON 字符串转 JSON 对象了。
2.1 JSON 字符串转 JSON 对象
常见的转化方式有三种:
obj = $.parseJSON(data);
obj = eval('('+data+')');
obj = JSON.parse(data);
看下转化后的结果:
可以看到,已经成功将 JSON 字符串转化成 JSON 对象了。其它两者是一样的,就不上图了。
2.2 推荐用 JSON.parse()
上面给出了三种方式,但推荐使用的只有 JSON.parse() ,其它两者都或多或少有些问题。
2.2.1 eval()
JavaScript 原生的 eval() 的原意是:eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码
但这里却用 eval('('+data+')') 来实现对象化。
为什么要 eval这里要添加('('+user+')') ”呢?
原因在于:eval本身的问题。 由于json是以”{}”的方式来开始以及结束的,在JS中,它会被当成一个语句块来处理,所以必须强制性的将它转换成一种表达式。
加上圆括号的目的是迫使eval函数在处理JavaScript代码的时候强制将括号内的表达式(expression)转化为对象,而不是作为语句(statement)来执行。举一个例子,例如对象字面量{},如若不加外层的括号,那么eval会将大括号识别为JavaScript代码块的开始和结束标记,那么{}将会被认为是执行了一句空语句。所以下面两个执行结果是不同的:
alert(eval("{}"); // return undefined
alert(eval("({})");// return object[Object]
上述这个答案是网上流传很广的,但由于自己的 JS 基础还不扎实,所以也还是不理解为什么可以通过 eval 实现对象化。(如有大牛路过,烦请解答一下,万分感谢)。
谈到 eval ,第一个念头就是最好不要使用,为什么呢?可以参考这篇文章:https://www.zhihu.com/question/20591877
eval 函数的描述可以参考 MDN 的文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval
2.2.2 Function 对象进行转化
在原生 JS 中还可以通过 Function 对象将 JSON 字符串转化成 JSON 对象( JavaScript 实在是博大精深 )
var json='{"name":"CJ","age":18}'
data =(new Function("","return "+json))();
这个方法实际中用的很少,最典型的应用是在 jQuery的 ajax 方法的 success 下实现对返回数据 data 的解析。参考自:https://www.cnblogs.com/chenguangliang/p/6688730.html
2.2.3 $.parseJSON()
该方法是 jQuery 中,不过从 jQuery 3.0 开始,就不再推荐使用了。用该方法转化也会存在一些问题,具体可参考 jQuery.parseJSON() 文档说明:http://www.css88.com/jqapi-1.9/jQuery.parseJSON/
2.2.4 JSON.parse()
JSON.parse() 是推荐使用的,详细内容也请参考 MDN 文档:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON
2.3 其实可以不用转换
在请求后端的一个 json 字符串时,可以通过在请求中指定 MIME 类型来直接得到 JSON 对象。在 jQuery 提供的 ajax 方法中通过设置 dataType 属性为 'json' 即可,如下图:
请求头如下:
当然,jQuery 提供了一个获取 json 数据更便捷的方法:$.getJSON()
关于这个方法的细节参考 jQuery API 文档吧:http://www.css88.com/jqapi-1.9/category/ajax/shorthand-methods/
3、PHP 中 json_encode 和 json_decode
通俗的讲:
json_encode 就是将 PHP 中的 对象/数组 序列化成符合 json 格式的字符串。
json_decode 就是将符合 json 格式的字符串反序列化成 对象/数组。
官方手册上详细说明参考:
json_encode:http://php.net/manual/zh/function.json-encode.php
json_decode:http://php.net/manual/zh/function.json-decode.php
这里要提一点,PHP 中的对象通常都是有类对应的,而通过 json_decode 从 标量(json 字符串) 中反序列化形成的对象,通常没有类与之对应,此时,PHP 中会有一个称为“stdClass”的类会收留该对象!
如下图:
反序列化成数组,只需要给 json_decode 添加第二个参数为 true 即可。
在 PHP 中使用 json 需要注意一点:由于 JSON 只接受 utf-8 编码的字符,所以 json_encode() 的参数必须是 utf-8 编码,否则会得到空字符或者null。当中文使用 GB2312 编码,或者外文使用 ISO-8859-1 编码时,需要特别注意!
编码问题可以参考我的另一篇博文:编码简述
4、JavaScript 中对象和数组
JS中,集合既可以用 数组 表示也可以用 对象 表示。但数组表示有序数据的集合,而对象表示无序数据的集合。如果数据的顺序很重要,就用数组,否则就用对象。
而 JS 中的关联数组其实就是对象,对象其实就是关联数组!
这和 PHP 中的是不一样的,PHP 中 索引数组 和 关联数组 都是数组。
这两点认识来自阮一峰的两篇博文:
5、总结
JSON 使用并不难,主要还是理解好表示的形式,在前后端交互时关键是理清到底接受到的是什么样的数据(字符串还是对象)。当然,本文并没有牵涉到 跨域 的问题,或许有机会再写。
给女朋友解决了问题,自己也理解更加透彻了,甚好甚好。
JavaScript 博大精深,要学好基础都还有漫漫长路要走,但幸运的是一直在路上。
发表评论
取消回复电子邮件地址不会被公开。 必填项已用*标注