JS循环嵌套函数无法访问迭代项问题求助(附代码)
问题分析与解决方案
这是JavaScript里非常经典的闭包陷阱问题,我帮你拆解一下原因和解决办法:
为什么会出现这个问题?
你的y回调函数是在循环过程中定义的,但它并不会立即执行——要等到nvd3渲染图表的时候才会被调用。而var声明的变量j是函数级作用域的,整个循环共享同一个j变量。当循环结束后,j的值已经变成了arrayOfJSONObjects.length(也就是你例子里的2),所以等到y函数执行时,它拿到的永远是这个最终值,自然取不到当前迭代项的invert属性。
解决方案1:用let声明循环变量(ES6+最简便)
把循环里的var j改成let j就行。let会在每次循环迭代中创建一个独立的块级作用域,这样每个y函数都会绑定当前迭代的那个j值,而不是共享同一个变量:
var listOfOptions = []; // 把var替换成let for (let j = 0; j < arrayOfJSONObjects.length; j++) { var options = { isInverted: arrayOfJSONObjects[j].invert, chart: { type: 'lineChart', height: arrayOfJSONObjects[j].height, y: function (d) { console.log(j); // 现在会正确输出0或1 if (arrayOfJSONObjects[j].invert == 1) { return (d.y * (-1)); } else { return d.y; } } } }; listOfOptions.push(options); }
解决方案2:用立即执行函数(IIFE)兼容旧环境
如果你的项目还不能用ES6,就用IIFE(立即执行函数表达式)把每次迭代的变量封装起来,强制创建独立作用域:
var listOfOptions = []; for (var j = 0; j < arrayOfJSONObjects.length; j++) { // 用IIFE捕获当前的j值,创建独立作用域 (function(currentIndex) { var options = { isInverted: arrayOfJSONObjects[currentIndex].invert, chart: { type: 'lineChart', height: arrayOfJSONObjects[currentIndex].height, y: function (d) { console.log(currentIndex); // 正确输出当前迭代的索引 if (arrayOfJSONObjects[currentIndex].invert == 1) { return (d.y * (-1)); } else { return d.y; } } } }; listOfOptions.push(options); })(j); // 把当前循环的j传入IIFE }
解决方案3:直接把invert存到options里(更直观)
你其实已经把isInverted存在了options对象里,完全可以在y函数里直接引用这个属性,不用依赖循环变量,代码可读性更高:
var listOfOptions = []; for (let j = 0; j < arrayOfJSONObjects.length; j++) { var currentInvert = arrayOfJSONObjects[j].invert; var options = { isInverted: currentInvert, chart: { type: 'lineChart', height: arrayOfJSONObjects[j].height, y: function (d) { // 直接用提前捕获的currentInvert变量 if (currentInvert == 1) { return (d.y * (-1)); } else { return d.y; } } } }; listOfOptions.push(options); }
或者如果你能确定this的指向(nvd3的chart回调里this通常指向chart对象,this.parent就是外层的options),还可以这样写:
y: function (d) { if (this.parent.isInverted == 1) { return (d.y * (-1)); } else { return d.y; } }
内容的提问来源于stack exchange,提问作者user2217057
相关产品推荐
相关产品推荐

