D3 v4中nest()函数生成带$符号的键,如何正确访问?
问题背景
我首次使用D3的d3.nest()函数绘制分级统计图,按国家和年份嵌套数据时,发现国家(如$AUS)和年份(如$1960)的键均被添加了$符号。已知这是D3 v4的预期行为,但想确认是否需通过dataByCountryByYear['$AUS']访问,同时想了解该场景下正确的对象键访问方式。
相关代码片段:
function ready(error, country_data, lfpr_data) { // converting strings to numbers where necessary lfpr_data.forEach(d => { d.year = +d.year d.female_lfpr = +d.female_lfpr; d.male_lfpr = +d.male_lfpr; }); // nesting by country and year i.e for each country all years beneath it var dataByCountryByYear = d3.nest() .key(function(d) { return d.country; }) .key(function(d) { return d.year; }) .map(lfpr_data); console.log(dataByCountryByYear['$AUS']) country_data.features.forEach(each_country => { each_country.properties.years = dataByCountryByYear[each_country.id] }); }
数据样例:
year country country_name region female_lfpr male_lfpr total_lfpr
1960 ABW Aruba Latin America & Caribbean NA NA NA
1960 AFG Afghanistan South Asia NA NA NA
1960 AGO Angola Sub-Saharan Africa NA NA NA
...
解答
首先明确:你看到的$前缀确实是D3 v4的预期行为——因为d3.nest().map()返回的不是普通JavaScript对象,而是D3专属的Map对象。它用$前缀来处理两种情况:一是非字符串类型的键(比如你转成数字的year),二是避免键名和Map对象自身的方法(比如get、set)冲突。
1. 正确的访问方式
你用dataByCountryByYear['$AUS']确实能拿到数据,但这只是D3 Map对普通对象属性访问的模拟,更规范、更可靠的方式是使用D3 Map内置的.get()方法:
// 获取AUS国家的所有年份数据 const ausData = dataByCountryByYear.get('AUS'); // 获取AUS国家1960年的数据(注意这里用数字1960,和你转换后的year类型匹配) const aus1960Data = ausData.get(1960);
这种方式不需要加$前缀,D3会自动处理键的类型匹配,也不用担心键名和方法名冲突的问题。
2. 修正你的代码
你当前代码中dataByCountryByYear[each_country.id]的写法存在隐患,建议改成.get()方法:
country_data.features.forEach(each_country => { // 用get()替代属性访问 each_country.properties.years = dataByCountryByYear.get(each_country.id); });
3. 可选:转成普通JavaScript对象
如果你更习惯用普通对象操作,可以把d3.nest()的输出换成普通对象,只需要把.map()改成.object():
var dataByCountryByYear = d3.nest() .key(function(d) { return d.country; }) .key(function(d) { return d.year; }) .object(lfpr_data);
这样生成的就是普通JS对象,键不会带$前缀,你可以直接用dataByCountryByYear['AUS']['1960']访问(注意这里年份是字符串,因为.object()会把所有键转成字符串类型)。
内容的提问来源于stack exchange,提问作者learner

