d3 - 来自闭包的tickFormat + mutable变量的问题?

时间:2016-08-02 17:53:07

标签: javascript d3.js

我有一个对象数组,它们将实际的刻度值映射到我希望刻度线的显示标签。换句话说,对象键入刻度值并给出显示值。

var tickMap = [{"27": 27, "28": 28, "29": 29, "30": 30, "31": "Test", "32": "Test2", "33": 33}, 
               {"50": 50, "58": "Test3", "66": 66, "74": 74, "82": 82, "90": 90}];

然后我循环遍历这个,并使用tickFormat属性,尝试返回每个tick值的显示值。 d是来自tickValue的汇总的实际数值:

for (var i = 0; i < tickMap.length; i++) {
  index = i;
  dimensions[i] = {
    'tickFormat': function(d) {
      return tickMap[index][d];
    },
    // other dimension properties are here, including arrays of 
    // the actual tick values in the tickValues property.
  }
};

但这似乎只适用于阵列中的第二个(或最后一个)轴。我没有使用tickMap[i][d],而是尝试全局声明index,然后将i的值分配给index,但这并没有帮助。

我也得到了错误&#34;可以从闭包中获取可变变量&#34;。

我不确定如何解决这个问题。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

您的问题是JS中的函数维护对其闭包中创建的实际变量的引用,而不是值。这意味着代码中的i 与每个i函数相同tickFormat(相同的内存位置),包含tickMap.length的值它在循环结束时得到了。

ES6解决方案

如果您可以使用ES6,只需使用let而不是var,一切都应该有效,因为let为每个循环迭代创建一个新变量,这意味着每个tickFormat函数会获得自己的i

副本
for (let i = 0; i < tickMap.length; i++) {
  dimensions[i] = {
    'tickFormat': function(d) {
      return tickMap[i][d];
    }
  }
};

ES5&amp;波纹管解决方案

否则,您必须手动执行相同操作,方法是将循环代码包装在Immediately Invoked Function Expression (IIFE)中并将i传递给它。这将在IIFE的参数中创建一个新变量,在每次迭代时,它将保存在创建IIFE时传递给IIFE的i值:

for (var i = 0; i < tickMap.length; i++) {
  dimensions[i] = (function iife(index) {
    return {
    'tickFormat': function(d) {
      return tickMap[index][d];
    };
  })(i); // <-- here you pass `i` as the `index`, maintaining a unique reference and thus the correct value for each `i`
};