本文核心讲解 JSON 数据遍历中for-in语句的使用规则、ECMAScript 规范的版本差异,以及for-in遍历 JSON 对象与数组的浏览器兼容问题,同时对比 JavaScript 中for循环与for-in遍历数组的核心区别,指出开发中的常见坑点并给出实用避坑建议,助力开发者规范使用遍历语法,避免因遍历问题导致的程序异常。
JSON 对象本质是 JavaScript 中的普通对象,而对象本身是无序的属性集合,因此使用for-in语句遍历对象属性时,遍历出的属性顺序大概率与对象定义时的书写顺序不一致,这一特性与 ECMAScript(ES)规范的版本更新直接相关。
明确描述:for-in语句的属性遍历顺序由对象定义时属性的书写顺序决定,此时遍历顺序是固定的,与定义顺序一致。
参考文档:ECMA-262 3rd Edition 中 12.6.4 The for-in Statement
for-in的属性遍历顺序,将遍历顺序的决定权交给各浏览器的 JavaScript 解析引擎,引擎可自行实现遍历逻辑。参考文档:ECMA-262 5rd Edition 中 12.6.4 The for-in Statement
新版本规范与早期版本的说明冲突,使得遵循 ES3 规范实现的解析引擎(部分旧浏览器),和遵循 ES5 规范实现的解析引擎(现代浏览器),处理for-in语句时的属性遍历顺序不一致。 开发核心原则:应尽量避免编写依赖对象属性顺序的代码,否则会因浏览器解析引擎不同,出现遍历结果不一致的兼容问题。
3. 典型示例:JSON 对象与数组的 for-in 遍历差异
var json1 = { "2":{"name":"第1条"}, "1":{"name":"第2条"}, "3":{"name":"第3条"} } var json2 = [ {"name":"第1条"}, {"name":"第2条"}, {"name":"第3条"} ] for(var i in json1){ alert(json1[i].name); } //正确 for(var i in json2){ alert(json2[i].name); } 实际开发中遇到的 JSON 数据分为纯数组型 JSON和嵌套字符串型 JSON,两种格式的遍历方式略有差异,以下是具体的代码实现示例,覆盖常见的业务场景。
直接定义数组型 JSON 数据,通过for-in遍历获取每个子对象的属性值,是最基础的 JSON 遍历方式:
var data=[{name:"a",age:12},{name:"b",age:11},{name:"c",age:13},{name:"d",age:14}]; for(var o in data){ alert(o); alert(data[o]); alert("text:"+data[o].name+" value:"+data[o].age ); } 部分场景下,JSON 数据的属性值是JSON 格式的字符串(需先解析为可操作的 JSON 对象 / 数组),此时需通过eval()或JSON.parse()解析后再遍历,以下是经典业务示例:
<script type="text/javascript">
function text(){
var json = {"options":"[{/"text/":/"王家湾/",/"value/":/"9/"},{/"text/":/"李家湾/",/"value/":/"10/"},{/"text/":/"邵家湾/",/"value/":/"13/"}]"}
json = eval(json.options)
for(var i=0; i<json.length; i++)
{
alert(json[i].text+" " + json[i].value)
}
}
</script>
示例中使用eval()解析 JSON 字符串,
现代开发更推荐使用JSON.parse(),原因如下:JS 中遍历数组有两种常用方式:标准 for 循环和for-in 循环,看似能实现相同的遍历效果,但二者的底层逻辑、遍历机制存在本质区别,且在特定场景下执行结果差异极大,是开发中极易踩坑的点。
var array = ['a'] //标准的for循环 for (var i = 1; i < array.length; i++) { alert(array[i]) } //foreach循环 for (var i in array) { alert(array[i]) }正常情况下,上述两种方式的遍历结果一致,均输出数组的所有元素,但二者存在多个底层区别,且在数组被扩展后会出现明显差异。
这是两种遍历方式最关键的区别,也是开发中最易引发 bug 的点。JavaScript 允许通过prototype扩展原生类的属性和方法,若数组(Array)的原型被扩展,for-in 循环会将扩展的属性 / 方法也遍历出来,而标准 for 循环仅遍历数组本身的元素。
// 扩展JavaScript原生的Array类,添加test方法 Array.prototype.test=function(){ } // 定义普通数组 var array = ['a', 'b', 'c'] // 方式1:标准的for循环 for (var i = 0; i < array.length; i++) { alert(array[i]) // 仅输出a、b、c,正常遍历数组元素 } // 方式2:for-in循环 for (var i in array) { alert(array[i]) // 输出a、b、c、test方法体,遍历了原型扩展的方法 }标准 for 循环仅遍历数组本身的索引元素,不受原型扩展的影响;而 for-in 循环会遍历数组对象的所有可枚举属性,包括数组自身的元素和原型上扩展的属性 / 方法,导致遍历结果包含非预期内容。
正在加载... ...