使用eval()解析JSON路径获取API价格时报语法错误的解决方法
问题:使用eval解析API响应路径时在数组索引场景下报错怎么解决?
我开发了一个从交易所API获取价格的部件,核心代码如下:
function getPrice(callback) { var Url = 'https://insert.api.url/'; var Key = 'insert.json.key'; request(Url, function(req) { var data = JSON.parse(req.responseText); var rate = eval("data." + Key); callback(rate); }); return true; } function request(Url, callback) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = (function(xhr) { return function() { callback(xhr); } })(xhr); xhr.open('GET', Url, true); xhr.send(); }
这段代码在部分API中能正常工作,比如对接Kraken API时:
var Url = 'https://api.kraken.com/0/public/Ticker?pair=XBTUSD'; var Key = 'result.XXBTZUSD.c[0]';
但在使用CoinMarketCap API时会触发eval的“expected token”语法错误,此时的配置是:
var Url = 'https://api.coinmarketcap.com/v1/ticker/bitcoin/'; var Key = '0[price_usd]';
请问这种情况该如何解决?
回答
嘿,这个问题我之前也碰到过!核心问题出在eval拼接后的语法不合法,咱们一步步来拆解和解决:
为什么会报错?
当你用eval("data." + "0[price_usd]")时,实际执行的代码是data.0[price_usd]——这在JavaScript里是纯纯的语法错误:
- 数字开头的属性/数组索引不能用点语法访问,得用方括号
data[0] - 正确的访问方式应该是
data[0].price_usd或者data[0]['price_usd']
而且eval本身就有安全风险(如果路径字符串被恶意篡改)和性能问题,完全没必要用它。
解决方案:自己实现路径解析函数
咱们写一个通用的函数,专门用来访问嵌套对象/数组里的属性,不管是点分隔还是括号语法都能处理:
function getNestedValue(obj, path) { // 先把[xxx]格式转换成.xxx,统一用点来分割路径 const normalizedPath = path.replace(/\[(['"]?)([^'"]+)\1\]/g, '.$2'); // 拆分路径成一个个片段 const segments = normalizedPath.split('.'); // 遍历片段,一层层访问嵌套结构 return segments.reduce((current, segment) => { // 如果当前层级不存在,直接返回undefined避免报错 if (current == null) return undefined; // 判断是不是数组索引(比如"0"这种数字字符串) const isArrayIndex = !isNaN(parseInt(segment)) && Number.isInteger(parseFloat(segment)); return isArrayIndex ? current[parseInt(segment)] : current[segment]; }, obj); }
然后修改你的getPrice函数,用这个函数替代eval:
function getPrice(callback) { var Url = 'https://api.coinmarketcap.com/v1/ticker/bitcoin/'; var Key = '0[price_usd]'; // 写成"0.price_usd"也能正常工作 request(Url, function(req) { // 加个try-catch处理JSON解析失败的情况 try { var data = JSON.parse(req.responseText); var rate = getNestedValue(data, Key); callback(rate); } catch (err) { console.error('解析数据失败:', err); callback(null); // 出错时给回调传null或者错误信息 } }); return true; } // 顺便给request函数加个请求成功的判断,避免处理错误响应 function request(Url, callback) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = (function(xhr) { return function() { // 只有请求完成且成功时才回调 if (xhr.readyState === 4 && xhr.status === 200) { callback(xhr); } } })(xhr); xhr.open('GET', Url, true); xhr.send(); }
额外优化小贴士
- 让组件更通用:把
Url和Key作为参数传入getPrice,这样不用每次修改函数就能对接不同API - 增强容错性:在
getNestedValue里可以加入更多错误处理,比如路径不存在时返回默认值 - 考虑用fetch替代XHR:现代浏览器支持
fetchAPI,写法更简洁,还支持Promise,比传统XHR好用多了
这样修改后,不管是Kraken的result.XXBTZUSD.c[0]还是CoinMarketCap的0[price_usd],都能正确解析到对应的值,而且彻底摆脱了eval的各种坑。
内容的提问来源于stack exchange,提问作者yamahama
相关产品推荐
相关产品推荐

