Câu hỏi D3 javascript Sự khác biệt giữa foreach và mỗi


Sự khác biệt giữa forEach và each trong D3js?


76
2017-11-20 02:36


gốc




Các câu trả lời:


Đầu tiên, .forEach() không phải là một phần của d3, nó là một hàm gốc của các mảng javascript. Vì thế,

["a", "b", "c"].forEach(function(d, i) { console.log(d + " " + i); });
// Outputs:
a 0
b 1
c 2

Và điều đó hoạt động ngay cả khi d3 không được tải trên trang.

Tiếp theo, d3's .each() hoạt động trên các lựa chọn d3 (những gì bạn nhận được khi bạn d3.selectAll(...)). Về mặt kỹ thuật, bạn có thể gọi .forEach() trên một lựa chọn d3, kể từ sau hậu trường, lựa chọn d3 là một mảng với các hàm phụ (một trong số đó là .each()). Nhưng bạn không nên làm điều đó vì:

  1. Làm như vậy sẽ không tạo ra hành vi mong muốn. Biết cách sử dụng .forEach() với lựa chọn d3 để tạo ra bất kỳ hành vi mong muốn nào sẽ yêu cầu sự hiểu biết thân mật về các hoạt động bên trong của d3. Vì vậy, tại sao làm điều đó, nếu bạn chỉ có thể sử dụng tài liệu, một phần công cộng của API.

  2. Khi bạn gọi .each(function(d, i) { }) trên một lựa chọn d3, bạn sẽ có nhiều hơn là chỉ d và i: hàm được gọi như vậy mà this từ khóa ở bất kỳ vị trí nào bên trong hàm đó trỏ đến phần tử HTML DOM được liên kết với d. Nói cách khác console.log(this) từ bên trong function(d,i) {} sẽ đăng nhập một cái gì đó như <div class="foo"></div> hoặc bất kỳ phần tử html nào. Và điều đó rất hữu ích, bởi vì sau đó bạn có thể gọi hàm này this để thay đổi thuộc tính, nội dung hoặc bất kỳ thứ gì của CSS. Thông thường, bạn sử dụng d3 để đặt các thuộc tính này, như trong d3.select(this).style('color', '#c33');.

Điều quan trọng nhất là, sử dụng .each() bạn có quyền truy cập vào 3 thứ bạn cần: d, this và i. Với .forEach(), trên một mảng (như trong ví dụ từ đầu) bạn chỉ nhận được 2 thứ (d và i) và bạn phải thực hiện một loạt công việc để kết hợp một phần tử HTML với 2 thứ đó. Và, trong số những thứ khác, là làm thế nào d3 là hữu ích.


160
2017-11-20 04:50



Lời giải thích rất hữu ích, cảm ơn! - Tyler Rick
Cảm ơn bạn đã viết một câu trả lời tuyệt vời, và để làm điều đó mà không bao gồm bất kỳ snark không cần thiết nào là phổ biến trên SO ... - Kevin H. Lin
Nên có một báo trước ở đây: khi bạn cần phạm vi khác nhau cho từ khóa 'this' nhưng bạn không cần datum trong hàm được gọi, lựa chọn [0] .forEach (...) thuận tiện hơn nhiều so với selection.each, điều này đòi hỏi cách giải quyết 'self = this' trong hàm cha nếu 'this' có ý nghĩa bên ngoài đơn thuần chỉ tham chiếu đến các phần tử DOM. - sdupton
@sdupton phạm vi cho this là một mối quan tâm trong nhiều trường hợp d3 nơi bạn vượt qua trong các hàm bậc cao hơn, bao gồm ví dụ selection.style("color", function(d,i) { /* here 'this' is a DOM element */ }). Tôi tin rằng đó là lý do tại sao các lớp d3 (như d3.svg.axis ví dụ) không sử dụng prototype phương pháp xác định các lớp - như một cách để tránh sự phụ thuộc vào this. Nhưng tôi không thấy như thế nào selection[0].forEach(...) tránh vấn đề này. Nó không phải là cùng một vấn đề? - meetamit
@sdupton, tuyệt vời - tôi không biết .forEach chấp nhận tham số thứ hai cho phạm vi this. Nó làm cho tôi nhận ra rằng bạn có thể sử dụng một cái gì đó tương tự-ish để đạt được hiệu quả tương tự với d3 của .each() bằng cách sử dụng javascript .bind() phương pháp. Ví dụ: phạm vi sau sẽ this đến window và sẽ console.log nó: selection.each(function() { console.log(this); }.bind(window)). - meetamit