Sự khác biệt giữa D3js forEach
và each
trong D3js là gì?
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 .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()
một vùng chọn d3, vì đằng sau, vùng chọn d3 là một mảng có các chức năng phụ (một trong số chúng là .each()
). Nhưng bạn không nên làm điều đó bởi vì:
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ẽ đòi hỏi sự hiểu biết sâu sắc về hoạt động bên trong của d3. Vậy tại sao phải làm điều đó, nếu bạn chỉ có thể sử dụng phần công khai, được lập thành tài liệu của API.
Khi bạn gọi .each(function(d, i) { })
một lựa chọn d3, bạn không chỉ có được d
và i
: hàm được gọi sao cho this
từ khóa ở bất kỳ đâu 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ì đó giống 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 trên this
đối tượng này để thay đổi các thuộc tính CSS, nội dung của nó hoặc bất cứ thứ gì. 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');
.
Vấn đề chính là, sử dụng .each()
bạn sẽ có được quyền truy cập vào 3 điều 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 điều ( d
và i
), và bạn sẽ 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 điều đó. Và đó, trong số những thứ khác, là cách d3 hữu ích.
this
là mối quan tâm trong nhiều trường hợp d3 nơi bạn chuyển các hàm bậc cao hơn, bao gồm cả ví dụ selection.style("color", function(d,i) { /* here 'this' is a DOM element */ })
. Tôi tin rằng đó là một phần lý do tại sao các lớp d3 (chẳng d3.svg.axis
hạn như) không sử dụng các 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 làm thế nào selection[0].forEach(...)
để tránh vấn đề này. Nó không phải là cùng một vấn đề?
.forEach
đã chấp nhận thông số thứ hai cho phạm vi this
. Nó khiến tôi nhận ra rằng bạn có thể sử dụng thứ gì đó tương tự để đạt được hiệu quả tương tự với của d3 .each()
bằng cách sử dụng .bind()
phương pháp của javascript . Ví dụ, phạm vi sau đây sẽ this
đến window
và sẽ console.log nó: selection.each(function() { console.log(this); }.bind(window))
.