D3 javascript Різниця між foreach та кожним


Відповіді:


178

По-перше, .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()). Але ви не повинні цього робити, оскільки:

  1. Це не призведе до бажаної поведінки. Знання того, як використовувати .forEach()з d3 виділення, щоб створити будь-яку бажану поведінку, зажадало б глибокого розуміння внутрішньої роботи d3. То навіщо це робити, якщо ви можете просто використовувати задокументовану, загальнодоступну частину API.

  2. При виклику .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.


17
Дякуємо за те, що написали чудову відповідь і за те, що зробили це, не включаючи жодного непотрібного ривка, який так поширений у SO ...
Кевін Х. Лін

1
Тут має бути застереження: коли вам потрібен різний масштаб для ключового слова 'this', але вам не потрібні дані у вашій викликаній функції, виділення [0] .forEach (...) набагато зручніше, ніж selection.each, що вимагає обходу "self = this" у батьківській функції, якщо "this" є значущим за межами просто посилання на елементи DOM.
sdupton

Обмеження @sdupton для thisє проблемою у багатьох сценаріях d3, коли ви передаєте функції вищого порядку, зокрема, наприклад selection.style("color", function(d,i) { /* here 'this' is a DOM element */ }). Я вважаю, що це частково, чому класи d3 (як, d3.svg.axisнаприклад) не використовують prototypeметоди визначення класів - як спосіб уникнути довіри this. Але я не бачу, як selection[0].forEach(...)уникає цього питання. Хіба це не та сама проблема?
meetamit

1
@meetamit ви можете явно вказати область 'this' для використання в Array.prototype.forEach з другим аргументом, переданим після функції, що викликається для кожного елемента. Коли ви пишете щось схоже на об'єктно-орієнтовану обгортку (я використовую класи ES6), втрата явного обсягу "this" може бути неприємною.
sdupton

2
@sdupton, круто - я не знав, що .forEachприйняв 2-й параметр для визначення масштабу this. Це змусило мене зрозуміти, що ви можете використовувати щось подібне для досягнення того ж ефекту з d3, .each()використовуючи .bind()метод javascript . Наприклад, наступна буде сфера , thisщоб windowі console.log його: selection.each(function() { console.log(this); }.bind(window)).
meetamit
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.