2015-06-02 14 views
7

Tôi đã có một số mã JS cũ để tạo cấu trúc đối tượng lồng nhau khổng lồ với []. Mã sẽ giống như thế nàyCó {} tiêu thụ ít bộ nhớ hơn [] cho các đối tượng lồng nhau trong Javascript không?

var data = []; 
data ["first"] = []; 
data ["first"]["second"] = []; 
data ["first"]["second2"] = "hello"; 

Đó là khoảng 250+ KB javascript, khá lớn. Khi tôi cố gắng quấn nó xung quanh với requirejs để tải vào một mô-đun requirejs khác, nó ném ra khỏi lỗi bộ nhớ.

Lỗi sẽ biến mất nếu tôi sử dụng {} nơi tôi đang sử dụng [].

Tôi đã làm một số bài tập về nhà vào ngày cuối tuần và nguyên nhân có vẻ là sử dụng các mảng liên quan như từ điển lồng nhau có thể bị rò rỉ trong Javascript vì mảng mở rộng đối tượng JS và có thể có nhiều nội dung cập nhật hơn khi thêm các đối tượng mới vào nó. Nhưng nó giải thích vấn đề tiêu thụ bộ nhớ? Hoặc nó liên quan đến cách Requirejs phân tích cú pháp đối tượng của mô-đun?

Tôi không có đủ kiến ​​thức về cách thực hiện công cụ bộ nhớ JS và so sánh giữa việc sử dụng {} hoặc [] trong công cụ trình duyệt, do đó khó có thể đạt được kết luận. Bất kỳ gợi ý hay gợi ý nào về cách sử dụng công cụ {} so với [] sẽ được hoan nghênh.

Cập nhật: Tôi đã thử một số sizeOf() qua nút ngày hôm qua. Tôi đã sử dụng tất cả những cái hiện có: "js-sizeof", "đối tượng sizeof", "sizeof"

Code:

var sizeof = require('object-sizeof'); 


var obj = []; 
obj['ball'] = 'hello'; 
obj['air'] = 'hello'; 
obj['ball']['fire'] = 'world'; 
obj['ball']['ice'] = []; 
console.log(sizeof(obj)); 

var obj2 = {}; 
obj2['ball'] = 'hello'; 
obj2['air'] = 'hello'; 
obj2['ball']['fire'] = 'world'; 
obj2['ball']['ice'] = []; 
console.log(sizeof(obj2)); 

Kết quả là

[]: 34 {} : 34

Kích thướcOf thực sự giống nhau., Nhưng có thể xảy ra sự cố khác với [] có thể kích hoạt vấn đề bộ nhớ. Tôi không chắc chắn nếu nó là requirejs phân tích cú pháp nó kích hoạt nó hoặc một số đường dẫn tối ưu hóa V8. Tôi không nghĩ rằng các công cụ Lint thậm chí còn đề xuất chống lại thực hành này nên nó khá mơ hồ theo cách nào là cách "đúng" trong thực tế

+1

chúng là tất cả các đối tượng, nhưng nếu có, '{}' sẽ tiêu thụ nhiều hơn vì bạn phải lưu trữ chuỗi khóa, thay vì chỉ là một chỉ số nguyên. –

+2

@MarcB: Sai. Điều đó sẽ phụ thuộc vào những gì bạn sử dụng phím, không cho dù đó là một mảng. – SLaks

+2

[Sử dụng mảng cho mục đích này chỉ là sai] (http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/). Không quan trọng là họ tiêu thụ nhiều bộ nhớ hơn. – Bergi

Trả lời

5

Không có thứ như "mảng được liên kết" trong JavaScript. [ 1, 2, 3 ] là cú pháp ngữ pháp mảng; nó khởi tạo một mảng. { foo: "bar" } là cú pháp ngữ pháp đối tượng; nó khởi tạo một đối tượng. Một điều không minh bạch của JavaScript, tuy nhiên, đó là Mảng cũng xảy ra được đối tượng, đó là lý do mã này "hoạt động":

var data = []; 
data["first"] = []; 
data["first"]["second"] = []; 

... nhưng bạn không nên làm điều đó, bởi vì nó không thực hiện bất kỳ giác quan. Bạn đang khởi tạo một mảng trống ([]), nhưng sau đó bạn không sử dụng nó như một mảng - bạn đang sử dụng nó như một đối tượng. Nếu bạn đang sử dụng tên thuộc tính (data["first"], tương đương với data.first) thay vì các phím số nguyên (data[0]), thì bạn muốn sử dụng một đối tượng. Không có kịch bản trong đó bạn nên khởi tạo một mảng khi bạn sẽ sử dụng nó như một đối tượng.

Theo quy tắc chung, nếu bạn cần mỗi mục có tên hoặc cần truy cập nhanh bằng tên, hãy sử dụng Đối tượng ({}) và sử dụng chuỗi cho khóa. Nếu bạn cần để có thể lặp qua các mục theo thứ tự, sử dụng một mảng với số nguyên cho các phím.

Tôi không biết nguyên nhân chính xác của lỗi ngoài bộ nhớ của bạn - đặc biệt là không nhìn thấy mã thực tế của bạn — nhưng chắc chắn là bạn nên sử dụng một đối tượng ({}), không phải là một mảng ([]) khi bạn không sử dụng các phím số nguyên.Các công cụ JavaScript tối ưu mọi thứ có thể, và các mảng và các đối tượng không là ngoại lệ, vì vậy không có gì ngạc nhiên khi bạn sử dụng một mảng theo cách mà động cơ không mong đợi nó có thể gây ra các vấn đề về hiệu năng hoặc bộ nhớ.

P.S. Như một vấn đề của phong cách, xem xét sử dụng ký hiệu sở hữu (hoặc "ký hiệu dấu chấm", có nghĩa foo.bar) thay vì ký hiệu subscript (tức foo["bar"]) khi giao dịch với các đối tượng:

var data = {}; 
data.first = {}; 
data.first.second = {}; 
data.first.second2 = "hello"; 

Đây chính là tương đương với mã bạn đăng, nhưng dễ đọc hơn và có thể giúp bạn nhớ rằng các đối tượng và mảng có cách sử dụng khác nhau. Bạn cũng có thể chỉ diễn tả điều này như một đối tượng duy nhất theo nghĩa đen:

var data = { 
    first: { 
    second: {}, 
    second2: "hello" 
    } 
}; 

Đây cũng là chính xác tương đương và giúp bạn nhìn thấy "cấu trúc" của đối tượng của bạn (miễn là bạn có kỷ luật về thụt đầu dòng).

Hầu hết các hướng dẫn kiểu JavaScript đều nói rằng bạn nên luôn sử dụng "ký hiệu chấm" trừ khi bạn có khóa sẽ gây ra lỗi cú pháp. Ví dụ: nếu bạn có thuộc tính có tên là "foo/bar", bạn rõ ràng không thể làm điều này:

var obj.foo/bar = 1; 

... vì đó là lỗi cú pháp. Vì vậy, bạn phải làm điều này:

var obj["foo/bar"] = 1; 

... hoàn toàn hợp lệ. Những trường hợp này có xu hướng là ngoại lệ, vì vậy tôi khuyến khích luôn sử dụng ký hiệu chấm trừ khi bạn phải sử dụng ký hiệu chỉ số.

+0

Hiểu biết của tôi là ary = [1,2,3] khởi tạo một đối tượng {1: 1, 2: 2, 3: 3} đó là lý do tại sao ary [10000000] = 123 hoạt động mà không làm hỏng máy của bạn. Tất cả các mảng đều là các đối tượng và tất cả các đối tượng hoạt động như các mảng liên kết (danh sách (LISP)) nhưng chúng có thêm một vài phương thức cho phép bạn khởi tạo chúng một cách hợp lý, lấy độ dài, v.v. hiện không đồng ý với lý do của bạn tại sao. Bạn có thể thuyết phục tôi bằng cách khác không? – superluminary

+0

Vâng, đó là chính xác những gì tôi đã viết trong đoạn đầu tiên của tôi. Và tôi không có động cơ để thuyết phục bạn, vì vậy tôi e rằng bạn sẽ phải không hài lòng với câu trả lời của tôi. –

+1

Tôi không có ý nói thô lỗ, tôi chỉ tin rằng mình đã nhầm lẫn. – superluminary

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