2010-03-30 57 views
21

Trong JavaScript, tại sao chuỗi số bát phân được đúc dưới dạng số thập phân? Tôi có thể truyền một chuỗi chữ hex bằng cách sử dụng Number() hoặc +, tại sao không phải là một bát phân?Tại sao một chữ bát phân không phải là một chuỗi ký tự thành một số?

Ví dụ:

1000 === +"1000" // -> true 
0xFF === +"0xFF" // -> true 
0100 === +"0100" // -> false - +"0100" gives 100, not 64 

Tôi biết tôi có thể phân tích với parseInt("0100" [, 8]), nhưng tôi muốn biết tại sao đúc không hoạt động như nó với hex và số tháng mười hai

Ngoài ra, có ai biết tại sao octal literals bị loại bỏ khỏi ECMAScript 5th Edition ở chế độ nghiêm ngặt không?

Trả lời

22

Tôi hơi muộn câu hỏi nhưng tôi nghĩ tôi có thể đưa ra câu trả lời hay.

Câu trả lời được chấp nhận không cho bạn biết thêm bất kỳ điều gì bạn thực sự biết và đề cập đến trong câu hỏi: Number(value) hoạt động như +value nhưng không phải là parseInt(value).

Điều quan trọng là phải biết rằng có một sự khác biệt ngữ nghĩa giữa loại chuyển đổiphân tích.

Tại sao chuỗi số bát phân được đúc dưới dạng số thập phân?

Number constructor called as a Function (Number(value)) và Unary + Operator (+value) đằng sau hậu trường sử dụng các hoạt động nội bộ ToNumber. Mục đích của các cấu trúc đó là loại chuyển đổi.

Khi ToNumber is applied to the String Type một sản xuất ngữ pháp đặc biệt được sử dụng, được gọi là StringNumericLiteral.

sản xuất này có thể giữ literals chỉ Decimal và literals Hexadecimal Integer:

... 

StrNumericLiteral ::: 
    StrDecimalLiteral 
    HexIntegerLiteral 

...

Ngoài ra còn có sự khác biệt về ngữ nghĩa giữa ngữ pháp này và ngữ pháp của "bình thường" NumericLiterals.

Một StringNumericLiteral:

  • Có thể trước và/hoặc sau khoảng trắng và/hoặc Terminators dòng.
  • Đó là số thập phân có thể có bất kỳ số 0 chữ số hàng đầu nào. không có octals!
  • Đó là số thập phân có thể đứng trước dấu + hoặc - để biểu thị ký hiệu của nó.
  • Trống hoặc chỉ chứa khoảng trắng được chuyển thành +0.

Bây giờ tôi sẽ đi với các chức năng parseIntparseFloat.

Mục đích của những chức năng rõ ràng là phân tích, đó là ngữ nghĩa khác nhau để loại chuyển đổi, ví dụ:

parseInt("20px");  // 20 
parseInt("10100", 2); // 20 
parseFloat("3.5GB"); // 3.5 
// etc.. 

là đáng nói rằng các thuật toán của parseInt thay đổi trong 5 ECMAScript Đặc tả Phiên bản, nó không còn diễn giải một số của radix dưới dạng bát phân chỉ để có số 0 đứng đầu:

parseInt("010"); // 10, ECMAScript 5 behavior 
parseInt("010"); // 8, ECMAScript 3 behavior 

Như bạn thấy, đã giới thiệu một incompatibility trong hành vi giữa triển khai ES3 và ES5, và như mọi khi được khuyến nghị sử dụng đối số gốc, để tránh bất kỳ vấn đề nào có thể xảy ra.

Bây giờ câu hỏi thứ hai của bạn:

Tại sao chữ bát phân được giảm từ ECMAScript 5th Edition trong chế độ nghiêm ngặt?

Trên thực tế, nỗ lực này của cách loại bỏ các chữ bát phân đến kể từ năm 1999. Các tác phẩm văn chương bát phân (OctalIntegerLiteralOctalEscapeSequence) đã được gỡ bỏ từ ngữ pháp của NumericLiteral s kể từ khi ECMAScript 3rd Edition specification, họ thể được bao gồm cho backwards compatibility (also in ES5) với các phiên bản tiêu chuẩn cũ hơn. Trên thực tế, chúng được bao gồm trong tất cả các triển khai chính, nhưng về mặt kỹ thuật, việc triển khai tuân thủ ES3 hoặc ES5 có thể chọn không bao gồm chúng, vì chúng được mô tả là không quy định.

Đó là bước đầu tiên, bây giờ ECMAScript 5 Strict Mode không cho phép chúng hoàn toàn.

Nhưng tại sao?

Bởi vì họ được coi là một lỗi dễ bị tính năng, và trên thực tế, trong quá khứ họ gây ra không chủ ý hoặc khó để bắt lỗi - cũng giống như cùng một vấn đề của octals ngầm của parseInt -.

Hiện tại, ở chế độ nghiêm ngặt, một chữ octal sẽ gây ra một ngoại lệ SyntaxError - hiện chỉ có thể quan sát được trong Firefox 4.0 Betas -.

+1

Đây là một câu trả lời tuyệt vời và nhiều hơn những gì tôi đã mong đợi ban đầu. Tôi đoán tôi bỏ qua 'StringNumericLiteral' trong spec, và tôi chắc chắn không biết rằng không gian trắng đã được cho phép. Đó chỉ là một trong những điều đó, tôi luôn mong đợi khoảng trắng sẽ dẫn đến * NaN *. –

+2

Cảm ơn @Andy, vâng, tôi thực sự thường thấy mọi người ngạc nhiên rằng ví dụ: 'isNaN (" \ t \ r \ n ")' trả về 'false';) – CMS

4

Bởi vì bạn không thực sự thực hiện truyền theo nghĩa thích hợp (JS không có đúc) - nó chỉ là loại tung hứng.

Khi bạn có bất kỳ chữ nào trong Javascript và ban hành một phương thức trên Javascript, một đối tượng được tạo phía sau hậu trường cho bạn.

"foo".toUpperCase() ví dụ, được thay thế bằng việc đánh giá các mã mà khoảng sẽ trông như thế này new String("foo").toUpperCase();

Kể từ chuỗi không thể được đánh giá với một nhà điều hành + unary, JS chuyển xâu thành của bạn đối với một số - và nó doesn Không sử dụng parseInt() hoặc parseFloat() nội bộ - bạn đã đoán - nó sử dụng Number().

Vì vậy, giá trị bạn thấy là những gì bạn thấy từ sự trở lại của Number(), có vẻ như không giả định octals.

+0

Cảm ơn Peter, tôi đã giả sử 'Số()' được sử dụng khi unary "đúc" (http://stackoverflow.com/ question/61088/hidden-features-of-javascript/2243631 # 2243631), nó có vẻ lạ với tôi rằng 'Số()' sẽ không chấp nhận bất kỳ chữ số được xâu chuỗi nào được định nghĩa bởi ngữ pháp. Nó chỉ có vẻ như nó sẽ có ý nghĩa hơn để tái sử dụng đằng sau hậu trường mã đã có cho phân tích cú pháp chữ số. Cảm ơn bạn đã biết thông tin về việc tạo đối tượng hậu trường, tôi đã đọc nó trước đây và điều đó khiến tâm trí tôi quên đi, thật dễ dàng để quên đi những điều này khi chúng được thực hiện một cách kỳ diệu cho bạn :-) –

+0

câu trả lời của tôi không được chấp nhận bởi vì hệ thống SE không cho bạn biết nó là cái gì, vì vậy tôi nghĩ tôi sẽ lịch sự và cho bạn biết 15 điểm của bạn đã đi đâu. CMS đã viết một câu trả lời hay giải thích lý do chi tiết hơn, vì vậy việc chấp nhận câu trả lời của ông có vẻ phù hợp. Xin lỗi, và cảm ơn câu trả lời của bạn :-) –

+0

@Andy không phải lo lắng - Tôi đồng ý - anh ấy có câu trả lời tốt hơn. Chúc mừng. –

1

Để giải thích lý do tại sao hỗ trợ bát phân đã được loại bỏ trong ES5, chủ yếu là do, với người mới làm quen hoặc không lập trình viên, cú pháp là không mong muốn. Hãy tưởng tượng sắp xếp theo chiều dọc một loạt các số (có thể được thêm vào), sử dụng các số 0 hàng đầu để sắp xếp chúng, ví dụ - nếu các số của bạn không sử dụng 8 hoặc 9, chúng sẽ được coi là bát phân. Đột nhiên mã của bạn tắt trong cỏ dại không có lý do rõ ràng! Đây là lý do tại sao hỗ trợ bát phân đã được gỡ bỏ. Một cú pháp bát phân khác có thể một ngày nào đó sẽ được thêm vào nếu nó không tạo ra một sự bất hạnh như vậy (tôi nghĩ rằng tôi nhớ thấy 0o755 là một ý tưởng của người rơm), nhưng bây giờ là bát phân.

Về sự không tương thích parseInt thay đổi được ghi chú trong các câu trả lời trước đây: không có triển khai nào đã thực hiện thay đổi này và tôi nghi ngờ không có triển khai nào được thực hiện. ES5 chủ yếu là căn cứ trong thực tế. Tính năng mới của nó thường không phá vỡ mã hiện có (ngoại trừ mã mới của khóa học phải cẩn thận trong việc sử dụng các tính năng mới không phá vỡ mã hiện có như là một phần của việc sử dụng) mà không cố gắng sử dụng các tính năng mới. Sự không tương thích của nó chủ yếu là không đáng kể, hoặc chúng không liên quan vì việc triển khai thực tế thực sự đã bỏ qua đặc điểm kỹ thuật vì các lý do tương thích. Nhưng không phải tất cả những điều không tương thích đều được thành lập tốt: một số có nhiều khát vọng hơn là hài hoà. Thay đổi đối với parseInt là một ví dụ về thay đổi đầy khát vọng. Nó phá vỡ mã hiện có mà mong đợi cú pháp bát phân, mà không có một cơ số rõ ràng, để phân tích cú pháp dưới dạng bát phân.

Trong khoảng thời gian vài ngày SpiderMonkey (công cụ JavaScript của Mozilla) đã thực hiện thay đổi nửa chừng để tạo parseInt, khi được gọi từ mã chế độ nghiêm ngặt, bỏ qua bát phân và hỗ trợ bát phân khi không gọi từ mã chế độ nghiêm ngặt. Điều này gần với những gì ES5 muốn, nhưng đó là một trở ngại rõ ràng để chuyển đổi mã không nghiêm ngặt sang chế độ nghiêm ngặt, nó có thể gây nhầm lẫn cho người dùng và - có lẽ thú vị nhất cho người thực hiện - điều đó có nghĩa là bạn không thể triển khai parseInt trong chính JavaScript (vì không có cách nào trong đặc tả để kiểm tra tính nghiêm ngặt của chức năng gọi điện), có thể là mong muốn vào một thời điểm nào đó (để giảm bề mặt tấn công, dễ triển khai, vv). Vì vậy, chúng tôi cởi bỏ sự phụ thuộc. (Tôi đã viết bản vá để làm cho parseInt phụ thuộc người gọi, và tôi đã xem xét bản vá để hoàn tác nó, sinh ra bằng cách thảo luận thêm sau khi bản vá ban đầu của tôi hạ cánh.) parseInt bây giờ phù hợp với ES3 một lần nữa, và cho trang web như nó, và ES5 của ngữ nghĩa có lẽ không tương thích với nó, tôi nghi ngờ chúng ta sẽ thay đổi. Do đó tôi nghi ngờ những người khác cũng sẽ thay đổi. (Tôi cũng khá chắc chắn rằng họ sẽ đồng ý với ước tính của chúng tôi về mức độ không tương thích của trang web với cú pháp vô hướng của ES5 về cú pháp bát giác tiềm ẩn trong parseInt và có lẽ với các lý do khác của chúng tôi. không chắc chắn họ sẽ làm theo, và tôi nghi ngờ họ sẽ được thông minh không.)

+0

+1, nhờ có cái nhìn sâu sắc hơn.Tôi đồng ý, ngữ pháp cho các số bát phân là khá nguy hiểm đối với những người không biết, không giống như tiền tố '0x' của ngữ pháp hex làm cho nó nổi bật so với các chữ số thập phân. –

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