2016-08-02 51 views
1

我有一个对象数组,它将实际的刻度值映射到我想要的刻度的显示标签上。换句话说,该对象被键入tick值并给出显示值。d3 - 可从闭包访问的tickFormat +可变变量问题?

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财产,试图为每个刻度值显示返回值。 dtickValue蜱的实际数值:

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. 
    } 
}; 

但这永远只能似乎数组中的第二个(或最后)轴工作。我试图在全局声明index,而不是使用tickMap[i][d],然后将值i指定为index,但这并没有帮助。

我也收到错误“可变变量可以从闭包访问”。

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

回答

1

你的问题是JS中的函数保持对在闭包中创建的实际变量的引用,而不是值。这意味着您的代码中的i将与tickFormat函数中的具有相同的i(相同的内存位置),包含循环结束时获得的值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 &波纹管解

否则,您必须手动执行此操作,方法是将您的循环代码封装在Immediately Invoked Function Expression (IIFE)中,并将i传入其中。这将创建IIFE的参数的新的变量创建时,将在每次迭代中,持有i已传递到IIFE值:

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` 
}; 
+0

你是男人!非常感谢你,这个解释非常有帮助。 – AndroidNoobie

+0

不客气,很高兴帮助:) – nem035