2012-07-30 26 views
55

Trong cuốn sách Javascript: The Good Parts bởi Douglas Crockford, đây là tất cả các tác giả đã nói về Tuyên bố tiếp tục:Tại sao các câu lệnh "tiếp tục" bị lỗi trong JavaScript?

Tuyên bố continue nhảy đến phía trên cùng của vòng lặp. Tôi chưa bao giờ thấy một đoạn mã không được cải thiện bằng cách tái cấu trúc mã để xóa câu lệnh continue.

Điều này thực sự gây nhầm lẫn cho tôi. Tôi biết Crockford có một số quan điểm rất có ý kiến ​​về JavaScript, nhưng điều này nghe có vẻ hoàn toàn sai với tôi.

Trước hết, continue không chỉ nhảy lên đầu vòng lặp. Theo mặc định, nó cũng tiến tới lần lặp tiếp theo. Vì vậy, không phải là tuyên bố của Crockford chỉ là thông tin hoàn toàn sai?

Quan trọng hơn, tôi không hoàn toàn hiểu tại sao continue thậm chí còn được coi là xấu. Bài đăng này cung cấp những gì có vẻ là giả định chung: Why is continue inside a loop a bad idea?

Mặc dù tôi hiểu làm thế nào để đọc được một số trường hợp nhất định, tôi nghĩ nó có khả năng làm cho mã dễ đọc hơn. Ví dụ:

var someArray=['blah',5,'stuff',7]; 
for(var i=0;i<someArray.length;i++){ 
    if(typeof someArray[i]==='number'){ 
     for(var j=0;j<someArray[i];j++){ 
      console.log(j); 
     } 
    } 
} 

Điều này có thể được refactored thành:

var someArray=['blah',5,'stuff',7]; 
for(var i=0;i<someArray.length;i++){ 
    if(typeof someArray[i]!=='number'){ 
     continue; 
    } 
    for(var j=0;j<someArray[i];j++){ 
     console.log(j); 
    } 
} 

continue không phải là đặc biệt có lợi trong ví dụ cụ thể này, nhưng nó chứng tỏ một thực tế rằng nó làm giảm độ sâu làm tổ. Trong mã phức tạp hơn, điều này có khả năng có thể tăng khả năng đọc.

Crockford không giải thích lý do tại sao continue không nên được sử dụng, vì vậy có ý nghĩa sâu sắc hơn đằng sau ý kiến ​​này mà tôi đang thiếu không?

+0

Từ khóa 'tiếp tục' là công cụ - hãy sử dụng công cụ này nếu có. SOmetimes nó là cần thiết, hầu hết thời gian nó không phải là. Thời gian duy nhất nó xấu là khi bạn không cần phải sử dụng nó nhưng đã quá lười biếng hoặc cẩu thả để làm điều đó một cách khác. – slugster

+0

Tôi có cảm giác tương tự và đó là lý do tại sao tôi thực hiện [post] của mình (http://stackoverflow.com/questions/30030033/continue-statement-confusion). Điều đã giúp tôi chỉ nghĩ về từ 'hop' khi sử dụng câu lệnh tiếp tục. Tôi nghĩ rằng ông Crawford đã sử dụng một từ ngữ nghèo nàn của sự lựa chọn ở đây khi thiết kế ngôn ngữ: P Đặc biệt là kể từ khi hop có thể áp dụng logic 'tiếp tục' phía sau nó. Nếu bạn nhảy qua một cái gì đó bạn thường xuyên tiếp tục. Hãy nghĩ về vận động viên chạy marathon như một sự tương tự tốt. –

+4

"Ông Crawford" không thiết kế ngôn ngữ. – rlemon

Trả lời

60

Tuyên bố là vô lý. continue có thể bị lạm dụng, nhưng thường là giúp khả năng đọc dễ đọc.

tiêu biểu sử dụng:

for (somecondition) 
{ 
    if (!firsttest) continue; 

    some_provisional_work_that_is_almost_always_needed(); 

    if (!further_tests()) continue; 

    do_expensive_operation(); 
} 

Mục đích là để tránh mã 'lasagna', nơi bạn có điều kiện lồng nhau sâu sắc.

Edited thêm:

Có, đây là cuối cùng chủ quan. Here's my metric for deciding.

Sửa lần cuối:

Ví dụ này là quá đơn giản, tất nhiên, và bạn luôn có thể thay thế điều kiện lồng nhau với chức năng cuộc gọi. Nhưng sau đó bạn có thể phải chuyển dữ liệu vào các hàm lồng nhau bằng tham chiếu, có thể tạo ra các vấn đề tái cấu trúc ít nhất là xấu như những cái bạn đang cố tránh.

+0

Tôi cũng muốn thêm rằng khả năng đọc là chủ quan và trong khi hầu hết mọi người dường như thích sử dụng tiếp tục, những người khác có thể không. Đối với cùng một lý do, mọi người ghét gotos, mà không phải là vốn ác (chỉ lạm dụng gotos là ác). – Wug

+0

Xem bài đăng của tôi [ở đây] (http://stackoverflow.com/questions/30030033/continue-statement-confusion). Tôi nghĩ rằng sự lựa chọn từ chỉ là sai, tôi nghĩ rằng 'hop' nên là một từ tốt hơn được sử dụng. Nhưng giờ đã quá trễ rồi! –

+0

Sử dụng 'tiếp tục' cũng cho phép đọc mã nhiều hơn theo kiểu * chức năng *, ví dụ:' for (a in b) {if (condition1) tiếp tục; nếu (điều kiện 2) tiếp tục; làm việc gì đó(); } 'tương tự như' b.filter (condition1) .filter (condition2) .forEach (a => ...); ' –

1

Cá nhân, tôi chưa bao giờ nghe bất kỳ điều gì xấu về việc sử dụng câu lệnh tiếp tục.Đúng là nó có thể (hầu hết thời gian) có thể dễ dàng tránh được, nhưng không có lý do gì để không sử dụng số. Tôi thấy rằng các vòng lặp có thể sạch sẽ hơn rất nhiều và dễ đọc hơn với các câu lệnh tiếp tục tại chỗ.

+0

Đúng vậy. Để thêm vào câu trả lời của bạn, trình thu thập nội bộ sẽ thêm tương đương với câu lệnh 'continue' vào cuối mỗi vòng lặp trong assembly được tạo ra. Vì vậy, thực tế, không chỉ là những tuyên bố tiếp tục không tệ, trên thực tế chúng thực sự rất tốt. –

2

Tiếp tục là một công cụ cực kỳ hữu ích để lưu các chu kỳ tính toán trong thuật toán. Chắc chắn, nó có thể được sử dụng không đúng cách nhưng như vậy có thể mỗi từ khóa hoặc cách tiếp cận khác. Khi cố gắng thực hiện, có thể hữu ích khi có một phương pháp nghịch đảo đối với sự phân kỳ đường dẫn với một câu lệnh có điều kiện. Tiếp tục có thể tạo thuận lợi cho nghịch đảo bằng cách cho phép các đường dẫn kém hiệu quả bị bỏ qua khi có thể.

8

Tôi là cá nhân ở phía bên kia so với đa số ở đây. Vấn đề thường không phải với các mẫu được hiển thị continue, nhưng với các mẫu lồng nhau sâu hơn, nơi các đường dẫn mã có thể khó nhìn thấy.

Nhưng ngay cả ví dụ của bạn với một continue không hiển thị cải thiện theo ý kiến ​​của tôi là chính đáng. Theo kinh nghiệm của tôi, một vài câu lệnh continuecơn ác mộng để tái cấu trúc sau này (ngay cả đối với ngôn ngữ tĩnh phù hợp hơn cho việc tái cấu trúc tự động như Java, đặc biệt là khi ai đó đặt ở đó break).

Vì vậy, tôi sẽ thêm một bình luận cho báo giá bạn đã cho:

Refactoring để loại bỏ continue tuyên bố inreases khả năng thêm bạn để cấu trúc lại.

Và các vòng trong thực sự được áp dụng tốt cho ví dụ: chức năng trích xuất. Việc tái cấu trúc như vậy được thực hiện khi vòng lặp bên trong trở nên phức tạp và sau đó continue có thể làm cho nó trở nên đau đớn.

Đây là những ý kiến ​​trung thực của tôi sau khi làm việc chuyên nghiệp trên các dự án JavaScript trong một nhóm, có những quy tắc mà Douglas Crockford nói về thực sự thể hiện thành tích của họ.

+4

Tôi không chắc chắn tôi biết những gì bạn có ý nghĩa. Bạn có nhớ đưa ra một ví dụ về nơi 'tiếp tục' sẽ trở thành" cơn ác mộng để tái cấu trúc "? Ngoài ra, bạn có ý nghĩa gì với "hàm trích xuất"? Đây có phải là mẫu thiết kế không? – twiz

+2

"chức năng trích xuất" (cũng có thể được googled theo "phương pháp trích xuất") là một kỹ thuật tái cấu trúc để trích xuất một phần của cơ thể của một hàm thành một hàm riêng biệt mới. Ngay cả mã đơn giản trong câu trả lời khác ở đây với 2 câu lệnh tiếp tục sẽ cần được viết lại (để loại bỏ các câu lệnh tiếp tục) để tạo ra một hàm mới ra khỏi phần thân của vòng lặp for. Khi bạn nhận được các cơ quan lớn hơn với nhiều câu lệnh tiếp tục lồng nhau, phải mất rất nhiều thời gian để làm sạch mã của bạn. –

5

Douglas Crockford có thể cảm thấy theo cách này bởi vì anh ta không tin vào nhiệm vụ trong một điều kiện. Trong thực tế, chương trình JSlint của ông thậm chí không cho phép bạn làm điều đó, mặc dù Javascript không. Ông sẽ không bao giờ viết:

Ví dụ 1

while (rec = getrec()) 
{ 
    if (condition1(rec)) 
     continue; 

    doSomething(rec); 
} 

nhưng, tôi đoán ông sẽ ghi cái gì đó như:

Ví dụ 2

rec = getrec(); 

while (rec) 
{ 
    if (!condition(rec)) 
     doSomething(rec); 

    rec = getrec(); 
} 

Cả của những công việc này, nhưng nếu bạn vô tình trộn những thứ này yles bạn nhận được một vòng lặp vô hạn:

Ví dụ 3

rec = getrec(); 

while (rec) 
{ 
    if (condition1(rec)) 
     continue; 

    rec = getrec(); 
} 

Đây có thể là một phần của lý do tại sao anh ấy không thích tiếp tục.

+0

Bạn có thể có một điểm, nhưng tôi tin rằng anh ta cũng thường phản đối 'trong khi 'vòng ở nơi đầu tiên. – twiz

+4

@twiz: Điểm của tôi cũng áp dụng cho vòng lặp 'for' và' do'. Chắc chắn anh ta tin vào * một số * loại vòng lặp! –

+0

'rec = getrec();' xuất hiện hai lần, vi phạm Đừng lặp lại chính mình. –

2

Trên thực tế, từ tất cả các phân tích có vẻ như: - (? Cũng có thể có một số lợi nhuận thực hiện)

  1. Nếu bạn có vòng cạn cảm thấy tự do để sử dụng tiếp tục khi và chỉ khi nó cải thiện khả năng đọc.
  2. Nếu bạn có vòng lặp lồng nhau sâu (có nghĩa là bạn đã có một viên bi để gỡ rối khi bạn tái yếu tố) tránh tiếp tục có thể chứng minh là có lợi từ một quan điểm độ tin cậy mã.

Để bảo vệ Douglas Crokford, tôi cảm thấy rằng đề xuất của ông có khuynh hướng nghiêng về phía defensive programming, trong tất cả sự trung thực có vẻ như là một cách tiếp cận tốt cho 'idiot-proofing' mã trong doanh nghiệp.

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