Posted at

D3のコードをES5からES6に書き直す場合はthisの扱いに注意


はじめに

ES5書かれていたd3のコードをES6に書き直した際に、文法的には間違っていないのにエラーが発生したのでメモ。


問題

selectAll()で取得した要素をeach()でループ処理する際に、各要素を適切に取得できていなかった。


エラー箇所

修正後

d3.selectAll('.hoge')

.each(d => {
const fuga = d3.select(this); // DOM内にhogeクラスはあるのに変数fugaがundefinedてしまう
fuga.append('piyo')
...
})

修正前

d3.selectAll('.hoge')

.each(function(d) {
const fuga = d3.select(this); // DOM内にhogeクラスはあるのに変数fugaがundefinedてしまう
fuga.append('piyo')
...
})


エラー内容

d3 select this createElementNS' of undefined"

select()で要素が適切に取得できていないため、DOM操作に失敗していた。


原因

アロー関数内のthisはスコープが従来と異なるため

詳細は以下の記事に詳しく書いてありました。

アロー関数はthisの値を語彙的に束縛する”らしい @ Qiita


対策


  1. 従来のES5の文法でfunctionを定義

  2. d3で用意されている引数を利用

2のやりかた

d3.selectAll('.hoge')

.each((d, i, nodes) => {
const fuga = d3.select(nodes[i]);
fuga.append('piyo')
...
})


おわりに

ES5の関数定義 = ES6のアロー関数定義 とひとくくりに考えていたためハマってしまった。よくよく考えると、文と式の違いだからスコープが違うのは当たり前か。