У чому різниця між forEachі eachв D3js?
Відповіді:
По-перше, .forEach()не є частиною d3, це вбудована функція масивів javascript. Тому,
["a", "b", "c"].forEach(function(d, i) { console.log(d + " " + i); });
// Outputs:
a 0
b 1
c 2
І це працює, навіть якщо d3 не завантажено на сторінку.
Далі d3 .each()працює над виділеннями d3 (що ви отримуєте, коли отримуєте d3.selectAll(...)). Технічно ви можете зателефонувати .forEach()на вибір d3, оскільки за кулісами вибір d3 - це масив із додатковими функціями (одна з них .each()). Але ви не повинні цього робити, оскільки:
Це не призведе до бажаної поведінки. Знання того, як використовувати .forEach()з d3 виділення, щоб створити будь-яку бажану поведінку, зажадало б глибокого розуміння внутрішньої роботи d3. То навіщо це робити, якщо ви можете просто використовувати задокументовану, загальнодоступну частину API.
При виклику .each(function(d, i) { })на вибір d3, ви отримуєте більше , ніж просто dі i: функція викликається , наприклад , що thisключове слово в будь-якому місці всередині цієї функції вказує на елемент HTML DOM , пов'язаний з d. Іншими словами, console.log(this)зсередини function(d,i) {}буде реєструвати щось на зразок <div class="foo"></div>будь-якого елемента html. І це корисно, оскільки тоді ви можете викликати функцію цього thisоб’єкта, щоб змінити його властивості CSS, вміст чи що завгодно. Зазвичай ви використовуєте d3 для встановлення цих властивостей, як у d3.select(this).style('color', '#c33');.
Основна ідея полягає в тому, що, використовуючи .each()ви отримаєте доступ до 3 речі , які потрібні: d, thisі i. За .forEach()допомогою масиву (як у прикладі з самого початку) ви отримуєте лише 2 речі ( dі i), і вам доведеться зробити купу роботи, щоб також пов’язати елемент HTML з цими 2 речами. І це, серед іншого, як корисний d3.
thisє проблемою у багатьох сценаріях d3, коли ви передаєте функції вищого порядку, зокрема, наприклад selection.style("color", function(d,i) { /* here 'this' is a DOM element */ }). Я вважаю, що це частково, чому класи d3 (як, d3.svg.axisнаприклад) не використовують prototypeметоди визначення класів - як спосіб уникнути довіри this. Але я не бачу, як selection[0].forEach(...)уникає цього питання. Хіба це не та сама проблема?
.forEachприйняв 2-й параметр для визначення масштабу this. Це змусило мене зрозуміти, що ви можете використовувати щось подібне для досягнення того ж ефекту з d3, .each()використовуючи .bind()метод javascript . Наприклад, наступна буде сфера , thisщоб windowі console.log його: selection.each(function() { console.log(this); }.bind(window)).