2010-06-21 37 views
6

Bạn có thể giải thích cách biểu thức JavaScript:Biểu thức JavaScript [1 [{}]] phân tích cú pháp chính xác như thế nào?

[1 [{}]] 

phân tích/đánh giá? Trong Firefox, Chrome, Konqueror và tê giác, dường như tạo một mảng với một phần tử đơn lẻ, undefined. Tuy nhiên, tôi không hiểu tại sao.

Trong Firefox:

[1 [{}]].toSource() 

sản xuất

[(void 0)] 

Thay thế 1 với giá trị JavaScript khác dường như mang lại kết quả tương tự.

Cập nhật: Tôi nghĩ tôi đã hiểu ngay bây giờ. codeka, Adrian và CMS làm rõ mọi thứ. Theo như tiêu chuẩn, tôi đã cố gắng đi qua ECMAScript 5.

  1. 1 [{}] là một người truy cập thuộc tính, do đó, nó được đề cập trong §11.2.1.
  2. baseReference là kết quả của việc đánh giá 1, vì vậy vẫn còn 1.
  3. baseValue = GetValue(baseReference) == 1.
  4. Tại GetValue (§8.7.1), Type(1) không phải là Reference (một tên giải quyết ràng buộc), do đó trở 1.
  5. propertyNameReference là kết quả của việc đánh giá {}, vì vậy một đối tượng rỗng.
  6. propertyNameValue = GetValue(propertyNameReference) == {}
  7. Tại CheckObjectCoercible(baseValue) (§9.10), chúng tôi trở lại (Số là đối tượng có thể cưỡng chế).
  8. propertyNameString = ToString(propertyNameValue)
  9. Tại ToString (§9.8), trở về ToString(ToPrimitive({}, hint String))
  10. Tại ToPrimitive (§9.1), trả lại kết quả của đối tượng [[DefaultValue]], đi qua PreferredType (string).
  11. Tại [[DefaultValue]] (§8.12.8), hãy để toString là kết quả của [[Get]] với đối số toString.
  12. Điều này được xác định tại §15.2.4.2 để trả về "[object " + [[Class]] + "]", trong đó [[Class]] là "Đối tượng" cho mẫu đối tượng mặc định.
  13. Vì có một số gọi là toString, chúng tôi gọi nó là đối số this{}.
  14. Trả về giá trị loại Reference, có giá trị cơ bản là BaseValue (1) và tên được tham chiếu là propertyNameString ("[object Object]").

Sau đó chúng tôi đi tới bộ khởi tạo mảng (§11.1.4) và xây dựng một mảng phần tử đơn lẻ với kết quả.

+1

Tôi không chắc chắn lý do tại sao điều này sẽ có giá trị JavaScript ... để bạn có được kết quả không thể đoán trước của động cơ * cố gắng * để xử lý nó. ..tình trạng bình thường đối với tôi. –

+0

@Nick, tôi cũng hoài nghi rằng đó là JS hợp lệ, và tôi sẵn sàng chấp nhận khả năng đó là hành vi không xác định đơn giản. Tuy nhiên, thực tế là tất cả 4 động cơ (có cài đặt riêng biệt) phân tích nó theo cùng một cách là ít nhất là thú vị. –

+1

@Matthew - câu trả lời của Adrian là một lời giải thích khá tốt về hành vi trong 4 trình duyệt đó, tôi vẫn không nghĩ rằng '[object]' là một accessor hợp lệ mặc dù ... vì vậy nó vẫn sẽ tùy thuộc vào từng công cụ sẽ xử lý trường hợp này. Đây là một trường hợp cạnh mặc dù, và tôi không thể tìm thấy bất cứ điều gì trong spec 3.1 nói rằng nó phải được xử lý chính xác như thế nào. –

Trả lời

7

Nếu chúng ta phá vỡ nó lên một chút, bạn sẽ thấy:

var foo = 1; 
var bar = {}; 
var baz = foo[bar]; 

[baz]; 

Tôi tin rằng đó là hợp lệ JavaScript, nhưng tôi không phải là một chuyên gia ...

+0

Tôi nghĩ bạn có nó. Tôi có thể không thấy điều này bởi vì nó không bình thường khi sử dụng một số như một đối tượng JavaScript, và đối tượng trống là một khóa bất thường. Bạn có bất cứ suy nghĩ nào về phần '[(void 0)]' không? –

+2

@Matthew: Tôi đoán là vì '1 [{}]' là không xác định, '(void 0)' chỉ đơn giản là dạng "kinh điển" của trình thông dịch đại diện cho "không xác định". –

8

Đó là vì bạn đang cố gắng lấy thuộc tính {} của đối tượng 1 và sau đó đặt nó vào một mảng. 1 không có thuộc tính {}, vì vậy 1[{}]undefined.

Nếu bạn thay thế 1 bằng một mảng, bạn sẽ thấy nó hoạt động như thế nào. Với 1[5]{}0, nó là [[5][0]].

Ngoài ra, hãy nhớ rằng obj['property'] giống với obj.property.

15

Đọc số OP and Nick comments, tôi nghĩ rằng tôi có thể mở rộng thêm một chút Adrian's answer để làm cho nó rõ ràng hơn.

JavaScript hoàn toàn hợp lệ.

JavaScript xử lý tên thuộc tính đối tượng dưới dạng chuỗi, đối tượng không được chứa các loại khác hoặc các đối tượng khác như phím, chúng chỉ là chuỗi.

Khung ký hiệu property accessor (MemberExpression [ Expression ]) ngầm chuyển đổi biểu thức trong ngoặc đơn vào một chuỗi, vì vậy:

var obj = {}; 
obj[{}] = "foo"; 
alert(obj["[object Object]"]); // foo 

Trong ví dụ trên bạn có thể thấy rằng tôi gán giá trị cho các {} bất động sản, và {}.toString() (hoặc {}+'') tạo ra chuỗi "[object Object] (qua Object.prototype.toString).

Khái niệm 1 [{}] ngầm chuyển đổi 1 Number nguyên thủy đến một đối tượng (điều này được thực hiện bởi các accessor tài sản) và nó sẽ tra cứu một tài sản mang tên "[object Object]" tra cứu tài sản được thực hiện trên Number.prototypeObject.prototype đối tượng, ví dụ:

1['toString'] === Number.prototype.toString; // true 

Cuối cùng, biểu thức 1 [{}] tự nó được đặt trong dấu ngoặc vuông ([1 [{}]]), đây thực sự là một mảng chữ.

Tóm lại đây là cách phân tích cú pháp đánh giá các biểu hiện:

[1 [{}]]; 
// ^The accessor expression is evaluated and converted to string 

[1 ["[object Object]"]]; 
//^A property lookup is made on an Number object 
// trying to access a property named "[object Object]" 

[undefined]; 
// ^the property is obviously not found 

    [undefined]; 
//^  ^
// An array literal is created with an element `0` which its value is `undefined` 
Các vấn đề liên quan