在原生JSON API普及之前,前端开发者解析JSON字符串大多依赖eval或者第三方库,安全隐患和兼容性问题层出不穷。jQuery提供的$.parseJSON方法曾是无数项目中最常用的反序列化入口,它看似只是JSON.parse的简单代理,实际内部却藏着一段针对ES5环境的异常捕获逻辑和针对旧浏览器的字符串校验逻辑。理解这段源码,不仅能搞清楚它做了什么防御,也能明白为什么后来的jQuery 3.x版本会把它标记为废弃。

parseJSON的源码实现与环境检测
jQuery在1.7到2.x版本中,parseJSON的实现大致分为两层:优先使用原生的JSON.parse,其次回退到基于eval的解析函数。整个判断发生在jQuery初始化阶段,而不是每次调用时动态检测,这是一个典型的性能优化手段——能力检测只做一次,结果缓存到内部变量中。
核心代码逻辑如下(以jQuery 1.11版本的实现为参考,简化后展示):
// dataPriv是内部数据缓存对象
var dataPriv = {};
// rvalidchars 等正则用于回退方案中的字符串安全性校验
var rvalidchars = /^[\],:{}\s]*$/,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
jQuery.parseJSON = function( data ) {
if ( data === null ) {
return data;
}
if ( typeof data === "string" ) {
// 去除BOM头,防止IE8把BOM传给JSON.parse
data = jQuery.trim( data );
if ( data ) {
// 优先尝试ES5原生的JSON.parse
if ( window.JSON && window.JSON.parse ) {
// 借用Function.prototype.call在全局严格模式下也能正确执行
return ( window.JSON.parse || null )( data );
}
// 回退方案:正则校验后eval
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "" ) ) ) {
return ( new Function( "return " + data ) )();
}
jQuery.error( "Invalid JSON: " + data );
}
}
jQuery.error( "Invalid JSON: " + data );
};注意几个细节:第一,传入null直接返回,因为历史上有些后端接口会用字符串"null"表示空值;第二,只接受string类型,如果传入对象或数字会直接抛错,这一点和JSON.parse的行为一致;第三,调用jQuery.trim去除首尾空白,同时这一步也会去掉字符串开头可能存在的UTF-8 BOM字符(\uFEFF),这是专门为老版本IE做的兼容,因为IE8之前的jScript引擎不会自动忽略BOM。
ES5环境下的异常处理与严格模式考量
现代浏览器(IE8+、Chrome、Firefox等)都实现了ES5规范的JSON对象,所以window.JSON && window.JSON.parse这个分支几乎是必然命中的。源码中有一段注释特别值得注意:在某些代码通过Google Closure Compiler编译、且开启严格模式检查的场景下,直接写JSON.parse(data)可能被认为调用的不是全局的JSON对象。因此jQuery使用了一个略显奇怪的写法:
// 优先走原生解析,|| null 保证在JSON.parse不存在时不报错 return ( window.JSON.parse || null )( data );
这种写法还有另一层防御意义:如果页面中某个第三方脚本意外地删除或覆写了window.JSON,代码不会在调用时抛出TypeError,而是按照条件判断走回退分支。当然在真实场景中JSON.parse一旦存在就不会被这段代码重新赋值,这里的防御更多是针对极端环境的兜底。
当传入的字符串不是合法JSON时,原生JSON.parse会抛出SyntaxError,jQuery并不会捕获这个异常再包装——它选择让异常直接冒泡给调用方。这是一个设计取舍:jQuery认为解析失败属于调用方的数据问题,框架不应该吞掉错误信息。所以在使用parseJSON时,如果你无法保证数据源的合法性,仍然需要自己包一层try catch:
try {
var obj = $.parseJSON( responseText );
console.log( obj.name );
} catch ( e ) {
// JSON.parse抛出的SyntaxError会传到这里
console.error( "响应数据不是合法的JSON:", e.message );
}另外一点容易被忽略:注释中提到的InvalidCharacterError。在部分旧版浏览器中,如果JSON.parse是使用new Function实现的垫片(polyfill),传入非法字符时抛出的可能是InvalidCharacterError而不是标准的SyntaxError。jQuery的文档提醒开发者不要依赖具体的错误类型,只判断是否抛异常即可。
回退方案的字符串校验机制与废弃原因
在不支持JSON对象的古老浏览器(IE7及以下)中,jQuery采用eval路线,但绝不是裸调eval。它先用一组正则把字符串中合法的部分替换掉:合法的转义序列替换成@,合法的字面量(字符串、数字、true、false、null)替换成],多余的左中括号清除,剩下的内容如果还能匹配^[\],:{}\s]*$,说明整个字符串只由结构符号和空白组成,才允许交给Function执行。这套校验源自Douglas Crockford在json.js中的实现,能有效阻止alert(1)这类代码注入。
但正则校验毕竟不是完整解析,它只能保证语法层面安全,无法保证语义完全符合JSON规范。比如单引号字符串、未加引号的键名在JavaScript字面量里合法,在JSON规范里非法,经过校验后仍会被eval解析成功。也就是说,回退方案比原生JSON.parse更宽松,同一份数据在不同浏览器下可能出现解析结果不一致的情况。
正是因为这些历史包袱,jQuery 3.0开始正式废弃$.parseJSON,官方建议直接使用JSON.parse。原生方法有引擎层面的优化,语法检查更严格,错误信息更准确。如果你的项目还在维护使用parseJSON的老代码,迁移时要注意两点:一是JSON.parse不接受null参数(会直接返回null但不会报错,行为一致),二是$.parseJSON会自动trim字符串,而JSON.parse不会,字符串开头带BOM或空白时前者能解析、后者会抛SyntaxError。理解了这些差异,你就能安全地完成替换,也能真正看懂jQuery这段封装十几年前留下的设计智慧。
jQuery parseJSONJSON.parse异常处理修改时间:2026-09-14 02:20:44