Tại sao dòng này hợp lệ trong javascript?
var a = 0[0];
Sau đó, alà undefined.
"0"của một new Number(0)đối tượng.
0[0]giá trị trả về
0["toString"]Thật tuyệt, cảm ơn bạn đã chỉ ra.
Tại sao dòng này hợp lệ trong javascript?
var a = 0[0];
Sau đó, alà undefined.
"0"của một new Number(0)đối tượng.
0[0]giá trị trả về
0["toString"]Thật tuyệt, cảm ơn bạn đã chỉ ra.
Câu trả lời:
Khi bạn làm như vậy 0[0], trình thông dịch JS sẽ chuyển đối tượng đầu tiên 0thành một Numberđối tượng và sau đó cố gắng truy cập vào thuộc [0]tính của đối tượng đó undefined.
Không có lỗi cú pháp vì cú pháp truy cập 0[0]thuộc tính được ngữ pháp ngôn ngữ cho phép trong ngữ cảnh này. Cấu trúc này (sử dụng các thuật ngữ trong ngữ pháp Javascript) là NumericLiteral[NumericLiteral].
Phần có liên quan của ngữ pháp ngôn ngữ từ phần A.3 của thông số kỹ thuật ECMAScript ES5 là:
Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
Vì vậy, người ta có thể theo dõi máy cắt thông qua quá trình này:
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
Và, tương tự, Expressioncuối cùng cũng có thể NumericLiteralnhư vậy sau khi tuân theo ngữ pháp, chúng tôi thấy rằng điều này được phép:
NumericLiteral [ NumericLiteral ]
Có nghĩa là đó 0[0]là một phần được phép của ngữ pháp và do đó không có Lỗi cú pháp.
Sau đó, tại thời điểm chạy, bạn được phép đọc một thuộc tính không tồn tại (nó sẽ chỉ được đọc là undefined) miễn là nguồn bạn đang đọc là một đối tượng hoặc có một chuyển đổi ngầm định thành một đối tượng. Và, một ký tự số thực sự có một chuyển đổi ngầm thành một đối tượng (một đối tượng Số).
Đây là một trong những tính năng thường không được biết đến của Javascript. Các loại Number, Booleanvà Stringtrong Javascript thường được lưu trữ nội bộ như nguyên thủy (không phải đối tượng toàn diện). Đây là một biểu diễn lưu trữ nhỏ gọn, bất biến (có thể được thực hiện theo cách này để có hiệu quả triển khai). Tuy nhiên, Javascript muốn bạn có thể coi những nguyên thủy này giống như các đối tượng với các thuộc tính và phương thức. Vì vậy, nếu bạn cố gắng truy cập một thuộc tính hoặc phương thức không được hỗ trợ trực tiếp trên nguyên thủy, thì Javascript sẽ tạm thời ép buộc nguyên thủy thành một loại đối tượng thích hợp với giá trị được đặt thành giá trị của nguyên thủy.
Khi bạn sử dụng cú pháp giống đối tượng trên một nguyên thủy chẳng hạn 0[0], trình thông dịch nhận ra đây là một quyền truy cập thuộc tính trên một nguyên thủy. Phản ứng của nó đối với điều này là lấy 0nguyên mẫu số đầu tiên và ép nó thành một Numberđối tượng toàn diện mà sau đó nó có thể truy cập vào thuộc [0]tính. Trong trường hợp cụ thể này, thuộc [0]tính trên đối tượng Number undefinedlà lý do tại sao đó là giá trị bạn nhận được 0[0].
Đây là một bài viết về tự động chuyển đổi một nguyên thủy thành một đối tượng cho mục đích xử lý các thuộc tính:
Cuộc sống bí mật của những người nguyên thủy Javascript
Dưới đây là các phần có liên quan của thông số kỹ thuật ECMAScript 5.1:
Ném TypeError nếu giá trị là undefinedhoặc null, nếu không trả về true.

- Đặt baseReference là kết quả đánh giá MemberExpression.
- Đặt baseValue là GetValue (baseReference).
- Đặt propertyNameReference là kết quả của việc đánh giá Biểu thức.
- Đặt propertyNameValue là GetValue (propertyNameReference).
- Gọi CheckObjectCoercible (baseValue).
- Đặt propertyNameString là ToString (propertyNameValue).
- Nếu sản xuất cú pháp đang được đánh giá được chứa trong mã chế độ nghiêm ngặt, hãy đặt nghiêm ngặt là đúng, nếu không đặt nghiêm ngặt là sai.
- Trả về giá trị kiểu Tham chiếu có giá trị cơ sở là baseValue và có tên được tham chiếu là propertyNameString và có cờ chế độ nghiêm ngặt là nghiêm ngặt.
Một phần hữu ích cho câu hỏi này là bước # 5 ở trên.
Điều này mô tả cách khi giá trị đang được truy cập là một tham chiếu thuộc tính, nó sẽ gọi ToObject(base)để lấy phiên bản đối tượng của bất kỳ nguyên thủy nào.
Này mô tả cách Boolean, Numbervà Stringnguyên thủy được chuyển đổi thành một hình thức đối tượng với [[PrimitiveValue]] tài sản nội bộ cho phù hợp.
Là một thử nghiệm thú vị, nếu mã như thế này:
var x = null;
var a = x[0];
Nó vẫn sẽ không ném ra SyntaxError tại thời điểm phân tích cú pháp vì đây là cú pháp hợp pháp về mặt kỹ thuật, nhưng nó sẽ ném ra một TypeError trong thời gian chạy khi bạn chạy mã bởi vì khi logic của Bộ truy cập thuộc tính ở trên được áp dụng cho giá trị của x, nó sẽ gọi CheckObjectCoercible(x)hoặc gọi ToObject(x)cái nào cả hai sẽ ném ra một TypeError nếu xlà nullhoặc undefined.
0[1,2]cũng hợp lệ, nó có nghĩa là gì? (Tôi cập nhật câu hỏi)
nullhoặc undefinedhoàn toàn ổn, ngay cả khi những thuộc tính đó không tồn tại.
0[2]
1,2nhưng lợi nhuận 2.
Giống như hầu hết các ngôn ngữ lập trình, JS sử dụng ngữ pháp để phân tích cú pháp mã của bạn và chuyển đổi nó sang dạng thực thi. Nếu không có quy tắc nào trong ngữ pháp có thể được áp dụng cho một đoạn mã cụ thể, nó sẽ tạo ra một Lỗi cú pháp. Nếu không, mã được coi là hợp lệ, bất kể nó có hợp lý hay không.
Các phần có liên quan của ngữ pháp JS là
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
Vì 0[0]tuân theo các quy tắc này, nó được coi là một biểu thức hợp lệ . Nó có đúng hay không (ví dụ như không gặp lỗi trong thời gian chạy) là một câu chuyện khác, nhưng đúng là như vậy. Đây là cách JS đánh giá các biểu thức như someLiteral[someExpression]:
someExpression(có thể phức tạp tùy ý)Number, chuỗi => Stringv.v.)get propertyhoạt động trên kết quả (2) với kết quả tên thuộc tính (1)Vì vậy, 0[0]được hiểu là
index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result
Dưới đây là một ví dụ về một biểu thức hợp lệ , nhưng không chính xác :
null[0]
Nó được phân tích cú pháp tốt, nhưng tại thời gian chạy, trình thông dịch không thành công ở bước 2 (vì nullkhông thể chuyển đổi thành một đối tượng) và gây ra lỗi thời gian chạy.
var x = null; var a = x[0];không tạo ra lỗi cú pháp, nhưng không tạo ra lỗi TypeError trong thời gian chạy.
0[0]trả về một giá trị thay vì không xác định
Có những tình huống mà bạn có thể chỉ số hợp lệ một số trong Javascript:
-> 0['toString']
function toString() { [native code] }
Mặc dù không rõ ràng ngay lập tức tại sao bạn muốn làm điều này, nhưng đăng ký trong Javascript tương đương với việc sử dụng ký hiệu chấm (mặc dù ký hiệu chấm hạn chế bạn sử dụng số nhận dạng làm khóa).
(0).toString(không gọi hàm). Đó là thuộc tính của kiểu số.
0sở hữu được truy cập và vì nó không tồn tại, undefinedlà hơn đúng như đã giải thích ở jfriend00.
0[0]sẽ trả về không xác định. Có khả năng là sẽ xảy ra nhưng không nhất thiết phải như vậy
Tôi chỉ muốn lưu ý rằng cú pháp hợp lệ này không phải là duy nhất đối với Javascript. Hầu hết các ngôn ngữ sẽ có lỗi thời gian chạy hoặc lỗi kiểu, nhưng đó không phải là lỗi tương tự như lỗi cú pháp. Javascript chọn trả về không xác định trong nhiều trường hợp mà ngôn ngữ khác có thể đưa ra một ngoại lệ, bao gồm cả khi đăng ký đối tượng không có thuộc tính của tên đã cho.
Cú pháp không biết kiểu của một biểu thức (ngay cả một biểu thức đơn giản như một ký tự số), và sẽ cho phép bạn áp dụng bất kỳ toán tử nào cho bất kỳ biểu thức nào. Ví dụ: cố gắng tạo chỉ số dưới undefinedhoặc nullgây ra một TypeErrortrong Javascript. Đó không phải là lỗi cú pháp - nếu điều này không bao giờ được thực thi (nằm ở phía sai của câu lệnh if), nó sẽ không gây ra bất kỳ vấn đề nào, trong khi lỗi cú pháp theo định nghĩa luôn luôn mắc phải tại thời điểm biên dịch (eval, Function, v.v. , tất cả được tính là biên dịch).
Bởi vì nó là cú pháp hợp lệ, và thậm chí là mã hợp lệ để được diễn giải. Bạn có thể cố gắng truy cập bất kỳ thuộc tính nào của bất kỳ đối tượng nào (và trong trường hợp này, 0 sẽ được chuyển thành đối tượng Số) và nó sẽ cung cấp cho bạn giá trị nếu nó tồn tại, nếu không thì không xác định. Tuy nhiên, cố gắng truy cập một thuộc tính của undefined không hoạt động, vì vậy 0 [0] [0] sẽ dẫn đến lỗi thời gian chạy. Điều này vẫn sẽ được phân loại là cú pháp hợp lệ. Có một sự khác biệt về cú pháp hợp lệ và những gì sẽ không gây ra lỗi thời gian chạy / thời gian biên dịch.
Không chỉ cú pháp hợp lệ mà kết quả không nhất thiết phải như undefinedvậy trong hầu hết các trường hợp, nếu không phải tất cả các trường hợp lành mạnh thì sẽ như vậy. JS là một trong những ngôn ngữ hướng đối tượng thuần túy nhất. Hầu hết các ngôn ngữ gọi là OO đều hướng lớp, theo nghĩa là bạn không thể thay đổi hình thức (nó gắn với lớp) của đối tượng sau khi được tạo, chỉ có trạng thái của đối tượng. Trong JS, bạn có thể thay đổi trạng thái cũng như hình thức của đối tượng và điều này bạn làm thường xuyên hơn bạn nghĩ. Khả năng này tạo ra một số mã khá khó hiểu, nếu bạn sử dụng sai. Các chữ số là bất biến, vì vậy bạn không thể thay đổi chính đối tượng, không phải trạng thái cũng như hình thức của nó để bạn có thể làm
0[0] = 1;
là một biểu thức gán hợp lệ trả về 1 nhưng không thực sự gán bất kỳ thứ gì, Số 0là không thay đổi. Mà tự nó là hơi kỳ quặc. Bạn có thể có một biểu thức giả định hợp lệ và chính xác (có thể thực thi), không gán bất kỳ thứ gì (*). Tuy nhiên, kiểu của chữ số là một đối tượng có thể thay đổi, do đó bạn có thể thay đổi kiểu và những thay đổi sẽ chuyển xuống chuỗi nguyên mẫu.
Number[0] = 1;
//print 1 to the console
console.log(0[0]);
//will also print 1 to the console because all integers have the same type
console.log(1[0]);
tất nhiên nó khác xa với danh mục sử dụng lành mạnh nhưng ngôn ngữ được chỉ định để cho phép điều này bởi vì trong các tình huống khác, việc mở rộng các khả năng đối tượng thực sự có ý nghĩa rất nhiều. Đó là cách các plugin jQuery kết nối với đối tượng jQuery để đưa ra một ví dụ.
(*) Nó thực sự gán giá trị 1 cho thuộc tính của một đối tượng, tuy nhiên không có cách nào bạn có thể tham chiếu đến đối tượng (xuyên tâm) đó và do đó nó sẽ được thu thập tại thẻ nexx GC
Trong JavaScript, mọi thứ đều là đối tượng, vì vậy khi trình thông dịch phân tích cú pháp nó, nó sẽ coi 0 như một đối tượng và cố gắng trả về 0 như một thuộc tính. Điều tương tự cũng xảy ra khi bạn cố gắng truy cập phần tử thứ 0 của true hoặc "" (chuỗi trống).
Ngay cả khi bạn đặt 0 [0] = 1, nó sẽ đặt thuộc tính và giá trị của nó trong bộ nhớ, nhưng khi bạn truy cập 0, nó được coi là một số (Đừng nhầm lẫn giữa việc coi là Đối tượng và số ở đây.)
true[0]hoặc""[0]