2012-07-17 29 views
8

Tôi chỉ duyệt source of JSLint và nhận thấy đoạn mã này:Có gì sai khi sử dụng câu lệnh được dán nhãn trong mã toàn cầu?

// Is this a labeled statement? 
//... 
if (next_token.labeled !== true || funct === global_funct) { 
    stop('unexpected_label_a', label); 
} //... 

Phần thú vị là sự so sánh funct === global_funct. Chạy đoạn mã sau thông qua JSLint ném một lỗi "bất ngờ nhãn", kể từ khi tuyên bố dán nhãn là trong bối cảnh thực hiện toàn cầu (Tôi biết, đó là một ví dụ ngu ngốc Here's a fiddle..):

loop: 
for (var i = 0; i < 10; i++) { 
    if (i === 5) { 
     break loop; 
    } 
} 

Nếu bạn đặt cùng đoạn trong một hàm, JSLint hoàn toàn hài lòng với nó và không ném một lỗi khi nó gặp nhãn. Here's a fiddle với mã sẽ vượt qua JSLint. Mã có thể được dán vào online version of JSLint nếu bạn muốn dùng thử.

Vì vậy, câu hỏi của tôi: có điều gì sai trái khi sử dụng câu lệnh được dán nhãn trong mã toàn cầu hay chỉ là một lựa chọn cá nhân khác của Crockford?

+0

Dường như đáng ngờ như biến thể trên "Goto được coi là có hại". –

+0

Tôi thực sự hy vọng điều này không được hỗ trợ trong javascript hiện đại: https://developer.mozilla.org/en/JavaScript/Reference/Statements/label – jbabey

+0

@RobertHarvey - Nó thực sự, nhưng tại sao hành xử khác nhau trong mã toàn cầu? –

Trả lời

3

Sau một số điều tra về hành vi của các tuyên bố được gắn nhãn, tôi nghĩ đây thực sự chỉ là sự lựa chọn của Crockford mà không có cơ sở thực tế nào. Theo như tôi có thể nói, không có tình huống nào có thể gây ra xung đột tên với các nhãn trong phạm vi toàn cầu (và đó dường như là lý do chính mà mọi người có thể nghĩ ra vì sao JSLint không cho phép nó - xem nhận xét về câu hỏi).

Các ES5 bang đặc tả sau trong section on labelled statements:

Việc sản xuất Định danh: Báo cáo được đánh giá bằng cách thêm Định danh vào tập nhãn của Tuyên Bố và sau đó đánh giá Tuyên Bố.

...

Trước khi tiến hành đánh giá một LabelledStatement, các chứa Tuyên Bố được coi là sở hữu một bộ nhãn sản phẩm nào, trừ khi nó là một IterationStatement hoặc một SwitchStatement, trong đó trường hợp nó được coi là sở hữu một bộ nhãn bao gồm phần tử đơn, empty.

Tôi thực hiện điều này có nghĩa là mọi câu lệnh đều có một bộ nhãn. Các mã định danh nhãn là độc lập với các biến số định danh và chức năng, do đó, nó được chấp nhận theo cú pháp để có một nhãn có cùng số nhận dạng như một biến trong cùng một phạm vi.Nói cách khác, đây là hợp lệ:

var label = "My Label"; 
label: 
for (var x = 1; x < 10; x++) { 
    break label; 
} 

Vì mỗi tuyên bố đã thiết lập nhãn riêng của mình, điều này cũng là hợp lệ:

label: 
for (var x = 1; x < 10; x++) { 
    //Looks for 'label' in label set of `break` statement, then `for` statement 
    break label; 
} 
label: 
for (var y = 5; y < 15; y++) { 
    //Same again. Will never look for label outside the enclosing `for` statement 
    break label; 
} 

Vì bạn có thể gắn nhãn bất kỳ tuyên bố (đó là vô nghĩa, nhưng nó có thể) , bạn có thể gắn nhãn một tuyên bố nhãn:

another: 
label: 
for (var y = 5; y < 15; y++) { 
    break label; 
} 

Khi điều này là trường hợp, các quốc gia đặc tả như sau:

Nếu chính sách LabelledStatement có bộ nhãn không trống, các nhãn này cũng được thêm vào bộ nhãn Bản sao kê trước đánh giá nó.

Trong đoạn mã trên, bộ nhãn của câu lệnh for chứa hai nhãn (anotherlabel). Có thể chia nhỏ thành hoặc các nhãn đó từ trong câu lệnh for.

Và cuối cùng, spec cũng khẳng định (nhấn mạnh thêm):

báo cáo đã được gán nhãn chỉ được sử dụng kết hợp với nhãn breakcontinue báo cáo. ECMAScript không có số goto tuyên bố.

Vì vậy, dựa trên tất cả những điều đó, tôi không thể nghĩ ra một cách có thể cho bất kỳ nhãn nào trong mã toàn cầu can thiệp vào mã toàn cầu khác. Tất nhiên, rất khó bạn sẽ muốn một chương trình có chứa nhiều nhãn với cùng một mã định danh và JSLint đã ngăn chặn điều đó bằng cách ném một lỗi "nhãn đã được xác định". Nhưng tôi không nghĩ có bất kỳ sự khác biệt nào với cách nó xử lý các câu lệnh có nhãn trong ngữ cảnh thực thi toàn cầu.

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