2013-08-09 24 views
6

Tôi đang cố gắng lấy một cơ sở mã đang hoạt động và làm cho nó hướng đối tượng bằng cách sử dụng JavaScript. Hệ thống của tôi lấy JSON chứa nhómcác mục trong mối quan hệ một-nhiều và trực quan hóa điều này trên một trang. Các mục có thể được di chuyển vào các nhóm khác nhau và vị trí của chúng trong các nhóm đó cũng cần phải được tính toán. Như vậy, các sự kiện sẽ cần phải được thiết lập mà nhận thức được cả các nhóm và vé xung quanh.Phụ thuộc thông tư giữa Lớp JavaScript và đối tượng jQuery

Tôi đang sử dụng John Resig's thiết lập kế thừa JavaScript đơn giản để thiết lập hai lớp, ItemGroup. Khi mỗi Item được khởi tạo, nó đề cập đến nó là phụ huynh Group. Vấn đề của tôi nảy sinh khi tôi muốn thiết lập sự kiện của tôi, và là cách dễ dàng nhất giải thích bằng các chức năng sau:

var Group = Class.extend({ 
    ... 
    // Calculate where to place the new item within the group 
    calculate_new_position: function(item) { 
    var pos = -1; 
    // Loop through all DOM items in groups body 
    $(".item", this.elBody).each(function(i) { 

     // Retrieve it's class object 
     var next = $(this).data("_obj"); 

     // Calculating things using the class reference 
     var lowerPrio = item.tData.priority < next.tData.priority, 
      lowerId = item.id < next.id; 

     if(lowerPrio || lowerId) { 
     pos = i; 
     return false; 
     } 
    }); 
    return pos; 
    }, 
    ... 
)}; 

Lưu ý việc sử dụng các .data("_obj") trong đoạn mã trên. Về cơ bản, khi tôi cần phải làm một cái gì đó như phân loại các mục, sau đó tôi cần phải biết đối tượng (mô hình) tương ứng với tất cả các mục của DOM (xem/điều khiển) trong nhóm. Bây giờ, tôi có thể thiết lập lớp học Group của mình để khi tạo mỗi Item Tôi thêm một tham chiếu đến nó từ trong số Group của mình (ví dụ: Group.items = [i1, i2...]), và sau đó thay vì lặp qua các phần tử DOM, tôi có thể lặp qua các trường hợp Item. Tuy nhiên tôi nghĩ rằng tôi muốn chạy vào các vấn đề tương tự xuống dòng, chẳng hạn như khi tôi muốn di chuyển một Item vào một khác nhau Group (như Group sẽ không biết về Item).

Câu chuyện dài ngắn: thực sự là nguy hiểm/ngây thơ/vô nghĩa khi có lớp học khi tạo thành phần tử DOM, sau đó lần lượt trỏ trở lại lớp học? Điều này cảm thấy như phụ thuộc vòng tròn, và một số cơn ác mộng đệ quy, nhưng có lẽ một tham chiếu đến một đối tượng không phải là một điều khủng khiếp như vậy. Nếu tôi đang làm bất cứ điều gì khác thực sự ngu ngốc, và có một cách đơn giản hơn nhiều, sau đó xin vui lòng chỉ ra rằng là tốt.

+0

Bạn đã xem cách Backbone.js thực hiện điều đó chưa? Đối tượng 'view' giữ tham chiếu đến' model' (Item của bạn, Class group) và DOM element 'el'. Có nhiều cách để thực hiện nó và Backbone.js không đề nghị bất kỳ một cách nào ở đây: http://backbonejs.org/#FAQ-tim-toady – vsr

Trả lời

2

Bất kỳ trình thu thập rác trình duyệt hiện đại nào đều có thể xử lý các tham chiếu vòng tròn. Đối tượng của bạn sẽ bị thu thập rác nếu bạn mất tất cả các tham chiếu đến đối tượng và xóa tất cả các nút HTML khỏi DOM (trong khi DOM của trình duyệt sẽ thấy tham chiếu đến đối tượng của bạn và ngăn không cho thu thập rác). Tuy nhiên, hãy cẩn thận với trình xử lý sự kiện, chúng có thể giữ lại sự tinh tế nếu bạn không loại bỏ chúng.

Tôi nghe một số phiên bản cũ hơn của IE có vấn đề với tham chiếu vòng tròn. Để biết thêm trong depht giải thích: Precise explanation of JavaScript <-> DOM circular reference issue

Từ câu trả lời rằng: .data jQuery() làm cho điều đáng tin cậy hơn vì các phiên bản cũ của trình duyệt IE có một vấn đề cụ thể với các thuộc tính đã được thêm vào một phần tử DOM và không xử lý hình tròn tham chiếu đúng cách liên quan đến dữ liệu trong các thuộc tính đó và do đó sẽ không giải phóng mọi thứ khi cần (rò rỉ). .data() hoạt động xung quanh điều đó bằng cách chỉ sử dụng một thuộc tính được thêm vào trên phần tử DOM là một chuỗi an toàn, không bị rò rỉ. Chuỗi đó sau đó là một khóa vào một đối tượng javascript có thể chứa tất cả các thuộc tính mà bạn muốn liên kết với phần tử DOM. Bởi vì các thuộc tính này đều được lưu trữ ở dạng javascript đơn giản, nơi các trình duyệt không có lỗi tham chiếu vòng tròn, làm theo cách này không gây rò rỉ.

Bạn có thể muốn xem xét D3.js nó thực hiện điều gì đó tương tự như bạn muốn.Nó liên kết dữ liệu với các phần tử DOM và cung cấp cách dễ dàng để tạo hình ảnh hóa: http://d3js.org/

Sử dụng D3 bạn có thể liên kết một dãy số với một mảng vòng tròn thẻ SVG và làm cho mỗi vòng tròn có bán kính dựa trên số của mảng liên kết với nó.

EDIT: Tôi quên đề cập rằng nếu bạn sử dụng $ .remove() thì trình xử lý sự kiện cũng sẽ bị xóa. Nhưng nếu bạn có ví dụ một trình xử lý sự kiện bên trong một bao đóng cũng có tham chiếu tới nút HTML (đã bị xóa) của bạn, nó sẽ không bị thu gom rác. Điều này thường không phải là một vấn đề lớn bởi vì một khi nó ở bên ngoài DOM, nó sẽ không tiêu tốn quá nhiều tài nguyên và không thể đệ quy lại những tham chiếu đóng cửa đó theo như tôi biết.

1

Khi sử dụng jQuery.data, nó không làm bất kỳ điều gì với phần tử dom. Phần tử dom chỉ lưu trữ một khóa chính nguyên thủy vào bộ nhớ đệm nội bộ jQuery, bất kể *. Các tài liệu tham khảo do đó bạn tạo là từ JS để JS:

var div = document.createElement("div"); 
$(div).data("asd", "daa") 
console.log(div[jQuery.expando]); 
//41 
console.log(jQuery.cache[41].data.asd); 
//"daa" 

(rõ ràng ở trên là jQuery internals và không nên dựa vào trong mã sản xuất)

Điều đó nói rằng, các dữ liệu sẽ bị rò rỉ ở đó nếu bạn không đi qua jQuery để làm tất cả các thao tác của bạn vì jQuery sẽ không được thông báo nếu bạn đi sau lưng nó.

Thực hành tốt nhất với các lớp tiện ích là cung cấp phương thức destroy loại bỏ tất cả các yếu tố chịu trách nhiệm, hủy liên kết mọi sự kiện được đính kèm và đặt tất cả tham chiếu DOM thành null.

* Nếu hoàn toàn không có sự kiện hoặc dữ liệu nào về phần tử, thì mục nhập không tồn tại. Nhưng nếu một mục nhập tồn tại vì bất kỳ lý do nào, thì việc sử dụng jQuery.data sẽ không tương tác với chính phần tử đó.

1

@ Câu trả lời của Hoffmann là tốt khi anh ấy đưa ra lời khuyên thực tế, với lời giải thích. Tôi đưa ra một quan điểm khác, lấy cảm hứng từ cách Backbone.js hoạt động. Đây là một sự mở rộng về những gì @vsr đề xuất trong bình luận ban đầu của họ.

Lực đẩy cơ bản: Không lưu trữ các đối tượng JS của bạn bằng $ .data().

Sử dụng $ .data() đề nghị bạn sử dụng $ (foo) để tìm kiếm đối tượng DOM, sau đó đi sâu vào tính chất của chúng để có được chức năng JS tùy chỉnh của bạn, mà có thể hoạt động trên các yếu tố DOM hơn để có được ít của họ chức năng tùy chỉnh. Điều này quá phức tạp và không hiệu quả.

Cách tiếp cận tốt hơn là tạo một bộ đối tượng "thuần túy JS", sử dụng bất kỳ cú pháp và cơ chế nào phù hợp với nhu cầu của bạn. Các đối tượng này sau đó có thể có thuộc tính trỏ đến phần tử DOM của chúng trong vài trường hợp cần thiết. Backbone (một lần nữa) cho thấy nó thực hành tốt để cũng cache phần tử DOM được chọn jQuery, là tốt. Việc xử lý các đối tượng "pure JS" này sẽ nhanh hơn và dễ dàng hơn để duy trì hơn là thông qua $ .data(). Nó cũng làm tăng sự trừu tượng giữa JS và HTML của bạn, đó là một điều tốt.

Hơn nữa, tôi đã tìm được cách làm việc tốt là KHÔNG làm tổ đối tượng của bạn, ngay cả khi chỉ có mỗi mối quan hệ một-nhiều. Không tạo thuộc tính "mục" của "nhóm". Thay vào đó, duy trì mảng của cả hai nhóm và các mặt hàng và có một (hoặc cả hai) quản lý hiệp hội bằng một tham chiếu chứ không phải là thành viên.

Các vấn đề liên quan