2013-04-11 54 views
12

Tôi đang viết một trình thông dịch JavaScript cho các thiết bị nhúng vô cùng hạn chế tài nguyên (http://www.espruino.com), và mỗi lần tôi nghĩ rằng tôi đã triển khai một số mã JavaScript chính xác, tôi nhận ra mình sai.JavaScript [] thực sự hoạt động như thế nào?

Câu hỏi của tôi bây giờ là khoảng []. Làm thế nào bạn sẽ thực hiện một trong những bit cơ bản nhất của JavaScript một cách chính xác?

Tôi đã xem xét thông số JavaScript và có thể tôi đã không tìm thấy đúng bit, nhưng tôi không thể tìm thấy câu trả lời hữu ích.

Trước đây tôi đã giả định rằng bạn đã thực sự có hai 'bản đồ' - một cho số nguyên và một cho chuỗi. Và chiều dài mảng là giá trị của số nguyên cao nhất cộng với một. Tuy nhiên điều này dường như không đúng, theo jsconsole trên chrome:

var a = []; 
a[5] = 42; 
a["5"]; // 42 
a.length; // 6 

mà còn:

var a = []; 
a["5"] = 42; 
a[5]; // 42 
a.length; // 6 

... Vì vậy, tuyệt vời - tất cả mọi thứ được chuyển thành một chuỗi, và chuỗi giá trị cao nhất đại diện cho một số nguyên được sử dụng (cộng một) để có được chiều dài? Sai rồi.

var a = []; 
a["05"] = 42; 
a.length; // 0 

"05" là số nguyên hợp lệ - ngay cả trong Octal. Vậy tại sao nó không ảnh hưởng đến chiều dài?

Bạn có phải chuyển đổi chuỗi thành số nguyên không và sau đó kiểm tra xem khi nào được chuyển đổi về chuỗi, nó có khớp không?

Có ai có tham chiếu đến thuật toán chính xác được sử dụng để lưu trữ và nhận các mục trong một mảng hoặc đối tượng không? Có vẻ như nó sẽ rất đơn giản, nhưng có vẻ như nó thực sự không phải vậy!

+6

[Tiêu chuẩn] (http://www.ecma-international.org/ecma-262/5.1/#sec-15.4) nói: "* Tên thuộc tính' P' (dưới dạng 'Chuỗi' value) là một chỉ mục mảng nếu và chỉ khi 'ToString (ToUint32 (P))' bằng với 'P' và' ToUint32 (P) 'không bằng với' 2 ** 32-1'. * ". – DCoder

+6

Nếu bạn đang viết một thông dịch viên, các giả định không nên được sử dụng. Bạn nên đọc thông số kỹ thuật. –

+0

Tại sao bạn không sử dụng các triển khai JS hiện có, mạnh mẽ và tuân thủ chuẩn, như V8? Những gì tôi đọc tại http://www.espruino.com/Performance nghe có vẻ khủng khiếp: -/ – Bergi

Trả lời

4

Như thông số kỹ thuật nói, và đã được ghi nhận bởi những người khác:

"Một tên thuộc tính P (dưới hình thức của một giá trị String) là một chỉ số mảng khi và chỉ khi ToString (ToUint32 (P)) bằng P và ToUint32 (P) không bằng 2^32-1. "

Đó của giải thích tại sao trong kịch bản của bạn "5" được coi là một chỉ số mảng và "05" không phải là:

console.log("5" === String("5" >>> 0)); 
// true, "5" is equal to "5", so it's an index 

console.log("05" === String("05" >>> 0)); 
// false, "05" is not equal to "5", so it's not an index 

Lưu ý: Zero-fill right shift là con đường ngắn nhất trong JS để có một sự thay thế của ToUint32, chuyển một số bằng không.

+0

Cảm ơn - điều này cũng giải thích vấn đề với độ dài mảng, các câu trả lời khác không thực sự giải quyết. Cảm ơn các liên kết đến spec cũng như DCoder –

3

Mảng chỉ là các đối tượng. Điều đó có nghĩa là chúng có thể có các thuộc tính bổ sung mà không được coi là các phần tử của mảng.

Nếu đối số khung vuông là số nguyên, nó sử dụng nó để thực hiện gán cho mảng. Nếu không, nó xử lý nó như một chuỗi và lưu trữ nó như là một thuộc tính trên đối tượng mảng.

Chỉnh sửa dựa trên nhận xét delnan và bình luận DCoder, đây là cách xác định JavaScript nếu nó là một chỉ số thích hợp cho một mảng (so với chỉ là một tài sản): http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

+0

Phần cuối cùng không hữu ích đặc biệt trừ khi bạn xác định * chính xác * "số nguyên" là gì và cái gì không.Ví dụ, là "05" một số nguyên và tại sao (không)? – delnan

4

Xem MDN

Cũng có thể trích dẫn các chỉ mục mảng JavaScript (ví dụ: năm ["2"] thay vì năm [2]), mặc dù không cần thiết. Tuy nhiên, số 2 trong năm [2] cuối cùng bị ép buộc thành một chuỗi bằng công cụ JavaScript , thông qua một chuyển đổi toString ngầm định. Nó là dành cho lý do này mà "2" và "02" sẽ đề cập đến hai khe cắm khác nhau trên phản đối những năm qua và các ví dụ sau đây ghi đúng:

console.log(years["2"] != years["02"]); 

Vì vậy, với a["5"] bạn đang truy cập mảng trong khi a["05"] đặt thuộc tính trên đối tượng mảng.

1

Mảng cũng là đối tượng.

Bằng cách này

a["05"] = 5; 

Bạn đang làm điều tương tự như:

a.05 = 5; 

Tuy nhiên, bên trên sẽ gây ra một lỗi cú pháp, như một tài sản theo quy định sau một dấu chấm không thể bắt đầu bằng một số.

Vì vậy, nếu bạn làm điều này:

a = []; 
a["05"] = 5; 

bạn vẫn có một trống mảng, nhưng tài sản của a tên 05 có giá trị 5.

Số xis an array index khi và chỉ khi ToString(ToUint32(x)) bằng x (vì vậy trong trường hợp "05" rằng yêu cầu không được đáp ứng).

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