Sự khác biệt giữa setTimeout có và không có dấu ngoặc kép và dấu ngoặc đơn


240

Tôi đang học JavaScript và gần đây tôi đã học về các sự kiện thời gian JavaScript. Khi tôi học được về setTimeoutW3Schools , tôi nhận thấy một nhân vật kỳ lạ mà tôi không chạy vào trước đó. Họ đang sử dụng dấu ngoặc kép và sau đó gọi hàm.

Thí dụ:

setTimeout("alertMsg()", 3000);

Tôi biết rằng dấu ngoặc kép và dấu ngoặc đơn trong JavaScript có nghĩa là một chuỗi.

Ngoài ra tôi thấy rằng tôi có thể làm như vậy:

setTimeout(alertMsg, 3000);

Với các dấu ngoặc đơn mà nó đề cập, không có dấu ngoặc đơn, nó được sao chép. Khi tôi đang sử dụng dấu ngoặc kép và dấu ngoặc đơn, nó sẽ trở nên điên rồ.

Tôi sẽ rất vui nếu ai đó có thể giải thích cho tôi sự khác biệt giữa ba cách sử dụng này setTimeout:

Với dấu ngoặc đơn:

setTimeout("alertMsg()", 3000);

Không có dấu ngoặc kép và dấu ngoặc đơn:

setTimeout(alertMsg, 3000);

Và thứ ba chỉ sử dụng dấu ngoặc kép:

setTimeout("alertMsg", 3000);

NB: Một nguồn tốt hơn để setTimeouttham khảo sẽ là MDN .


5
@Jefffrey rằng trang web w3fools không nói rằng nội dung đó sai, chỉ là nó có thể bị lỗi thời và thiếu một số nội dung mới hơn. Nên sử dụng như một tài liệu tham khảo cho (hoặc để tìm hiểu) các công cụ cốt lõi. Tôi có thể hiểu mọi người đang thất vọng bởi cách họ cố gắng có vẻ như họ là một phần của w3, nhưng điều đó không làm mất đi nội dung. Nó được bố trí độc đáo và dễ đọc với các ví dụ rõ ràng, hoàn hảo cho các noobs.
Matthew

14
@Matthew "Tuy nhiên, chúng tôi cảm thấy rằng W3Schools đang gây hại cho cộng đồng với thông tin không chính xác." - trong ba dòng đầu tiên.
Giày

1
@Jefffrey vâng tôi đã thấy điều đó nhưng thấp hơn ở nơi họ giải thích những gì họ không thích về nó, trong phần "W3Schools là rắc rối", không có lý do nào trong số ba lý do họ đưa ra có liên quan đến thông tin không chính xác. Họ không có một ví dụ duy nhất về bất cứ điều gì thực sự "sai". Khiếu nại của họ là họ không nói rõ ràng rằng họ không liên kết với w3, họ tính phí cho các chứng nhận không được công nhận và họ không cập nhật nhanh chóng với nội dung mới (ví dụ html 5).
Matthew

10
@Matthew, thông tin lỗi thời, bằng các ngôn ngữ tinh vi như Javascript, SQL hoặc PHP, là những gì hướng dẫn hàng loạt lập trình viên khao khát bám vào các công nghệ cũ và có khả năng nguy hiểm (như mysql_phần mở rộng của PHP) trong đó dòng câu hỏi SO chỉ là một ví dụ. IIRC cũng có một số lỗi rất tinh vi trong phần SQL, nhưng đã gần một năm kể từ lần cuối tôi truy cập trang web và rất nhiều trong số đó cũng có thể được sửa. Và ngay cả khi tất cả những điều trên là hoàn hảo, tôi vẫn sẽ không quảng cáo một trang web cố lừa dối mọi người bằng hành vi gian lận chứng chỉ của họ.
Giày

4
các chứng chỉ mờ ám sang một bên, đó là một nguồn tài liệu tham khảo hợp lý và nó phản tác dụng với toàn bộ quan điểm của SO để đi khắp nơi tố cáo chúng.
worc

Câu trả lời:


382

Sử dụng setIntervalhoặcsetTimeout

Bạn nên chuyển một tham chiếu đến một hàm làm đối số đầu tiên cho setTimeouthoặc setInterval. Tài liệu tham khảo này có thể ở dạng:

  • Một chức năng ẩn danh

    setTimeout(function(){/* Look mah! No name! */},2000);
  • Tên của một chức năng hiện có

    function foo(){...}
    
    setTimeout(foo, 2000);
    
  • Một biến chỉ đến một chức năng hiện có

    var foo = function(){...};
    
    setTimeout(foo, 2000);
    

    Xin lưu ý rằng tôi đặt "biến trong một hàm" tách biệt với "tên hàm". Không rõ ràng rằng các biến và tên hàm chiếm cùng một không gian tên và có thể ghi đè lên nhau.

Tranh luận

Để gọi một hàm và truyền tham số, bạn có thể gọi hàm bên trong hàm gọi lại được gán cho bộ hẹn giờ:

setTimeout(function(){
  foo(arg1, arg2, ...argN);
}, 1000);

Có một phương pháp khác để chuyển các đối số vào trình xử lý, tuy nhiên nó không tương thích với nhiều trình duyệt .

setTimeout(foo, 2000, arg1, arg2, ...argN);

Bối cảnh gọi lại

Theo mặc định, ngữ cảnh của hàm gọi lại (giá trị thisbên trong hàm được gọi bởi bộ định thời) khi được thực thi là đối tượng toàn cục window. Nếu bạn muốn thay đổi nó, sử dụng bind.

setTimeout(function(){
  this === YOUR_CONTEXT; // true
}.bind(YOUR_CONTEXT), 2000);

Bảo vệ

Mặc dù có thể, bạn không nên chuyển một chuỗi đến setTimeouthoặc setInterval. Đi qua một chuỗi làm setTimeout()hoặc setInterval()sử dụng một chức năng tương tự để eval()thực thi chuỗi như kịch bản , làm cho độc đoán và có khả năng gây hại thực hiện kịch bản tốt.


Tôi đã học được rằng khi bạn chỉ sử dụng tên hàm thì chức năng được sao chép, vậy tại sao bạn lại nói ở ví dụ đầu tiên rằng setTumeout foo (hàm) truyền tham chiếu mà hàm tôi đã nghiêng được sao chép. và bạn có thể cao hơn tôi xin vui lòng về eval xin vui lòng.
dùng1316123

41
@ user1316123 chức năng không bao giờ được sao chép. tương tự với các đối tượng và mảng. chúng được thông qua tham chiếu . bạn nên ngừng đọc w3schools. họ đang làm hại nhiều hơn là tốt
Joseph

4
Các hàm @JosephtheDreamer các đối tượng. "Một tên hàm" và "Một biến đề cập đến một hàm" là điều tương tự. Ngoài ra, bạn có thể truyền trực tiếp các tham số cho setTimeout (không cần phải bọc lambda cho nó (mặc dù như bạn đã nói - các trình duyệt mới hơn). Ngoài ra, vấn đề không nằm ở việc cho phép người dùng thực thi tập lệnh (dù sao họ luôn có thể thực hiện việc này), đó là bằng cách chấp nhận đầu vào từ khác người sử dụng và chạy như kịch bản người dùng có thể tự mình luôn luôn chỉ cần mở giao diện điều khiển và thực hiện tùy tiện JavaScript..
Benjamin Gruenbaum

@BenjaminGruenbaum Tôi sắp đưa ra một nhận xét gần như giống hệt với câu thứ hai của bạn. Cười :)
ErikE 16/07/13

2
Tôi không nhận ra rằng bạn cần sử dụng một chức năng để setTimeout hoạt động bình thường. Cám ơn giải thích rõ ràng.
Matt Dell

3

Tôi nghĩ rằng hàm setTimeout mà bạn viết không được chạy. nếu bạn sử dụng jquery, bạn có thể làm cho nó chạy chính xác bằng cách thực hiện điều này:

    function alertMsg() {
      //your func
    }

    $(document).ready(function() {
       setTimeout(alertMsg,3000); 
       // the function you called by setTimeout must not be a string.
    });

tôi nghĩ giống như bạn nhưng liên kết w3schools.com/js/js_timing.asp nói về ai đó khác
user1316123

Nếu tôi hiểu chính xác khi tôi sử dụng Brackets, tôi chỉ có thể tham khảo chức năng có chứa phương thức setTimeout có phải là chức năng có sẵn tại dấu ngoặc chỉ trong phạm vi cục bộ không?
dùng1316123

2

Hoàn toàn đồng ý với Joseph.

Đây là một mẹo để kiểm tra điều này: http://jsfiddle.net/nicocube/63s2s/

Theo ngữ cảnh của fiddle, đối số chuỗi không hoạt động, theo ý kiến ​​của tôi vì hàm này không được xác định trong phạm vi toàn cục.


w3schools.com/js/js_timing.asp nếu bạn có thể nhập vào liên kết xin vui lòng và xem becouse Joseph nói nguy hiểm của nó, nhưng nếu bạn nhập vào liên kết làm việc của nó
user1316123

Các bạn vui lòng xem cái này: quirksmode.org/js/this.html liên kết này nói rằng một func có thể được sao chép
user1316123

Vâng, nó có thể, bởi vì hàm là đối tượng trong JS. Vấn đề với eval là nó sẽ đánh giá trong bối cảnh toàn cầu, và không thể có được bối cảnh địa phương xảy ra với một câu đố.
Nicocube

bạn có thể giải thích trong một số từ về eval xin vui lòng.
dùng1316123


1

Điều gì xảy ra trong thực tế trong trường hợp bạn truyền chuỗi dưới dạng tham số đầu tiên của hàm

setTimeout ( 'string', number)

là giá trị của param đầu tiên được đánh giá khi đến lúc chạy (sau khi numbermiliseconds trôi qua). Về cơ bản nó bằng

setTimeout ( eval('string'), number)

Đây là

một cú pháp thay thế cho phép bạn bao gồm một chuỗi thay vì một hàm, được biên dịch và thực thi khi hết giờ. Cú pháp này không được khuyến nghị vì những lý do tương tự khiến việc sử dụng eval () trở thành rủi ro bảo mật.

Vì vậy, các mẫu mà bạn giới thiệu không phải là mẫu tốt và có thể được cung cấp trong các ngữ cảnh khác nhau hoặc chỉ là lỗi đánh máy đơn giản.

Nếu bạn gọi như thế này setTimeout(something, number), tham số đầu tiên không phải là chuỗi, mà là con trỏ tới một cái gì đó được gọi something. Và một lần nữa nếu somethinglà chuỗi - thì nó sẽ được đánh giá. Nhưng nếu đó là chức năng, thì chức năng sẽ được thực thi. mẫu jsbin


0
    ##If i want to wait for some response from server or any action we use setTimeOut.

    functionOne =function(){
    console.info("First");

    setTimeout(()=>{
    console.info("After timeOut 1");
    },5000);
    console.info("only setTimeOut() inside code waiting..");
    }

    functionTwo =function(){
    console.info("second");
    }
    functionOne();
    functionTwo();

## So here console.info("After timeOut 1"); will be executed after time elapsed.
Output:
******************************************************************************* 
First
only setTimeOut() inside code waiting..
second
undefined
After timeOut 1  // executed after time elapsed.

-1

Với dấu ngoặc đơn:

setTimeout("alertMsg()", 3000); // It work, here it treat as a function

Không có dấu ngoặc kép và dấu ngoặc đơn:

setTimeout(alertMsg, 3000); // It also work, here it treat as a function

Và thứ ba chỉ sử dụng dấu ngoặc kép:

setTimeout("alertMsg", 3000); // It not work, here it treat as a string

function alertMsg1() {
        alert("message 1");
    }
    function alertMsg2() {
        alert("message 2");
    }
    function alertMsg3() {
        alert("message 3");
    }
    function alertMsg4() {
        alert("message 4");
    }

    // this work after 2 second
    setTimeout(alertMsg1, 2000);

    // This work immediately
    setTimeout(alertMsg2(), 4000);

    // this fail
    setTimeout('alertMsg3', 6000);

    // this work after 8second
    setTimeout('alertMsg4()', 8000);

Trong ví dụ trên, hàm alertMsg2 () đầu tiên gọi ngay lập tức (chúng tôi sẽ hết thời gian 4S nhưng nó không làm phiền) sau cảnh báo đóMsg1 () (Đợi thời gian là 2 giây) rồi alertMsg4 () (Thời gian chờ là 8 giây) nhưng alertMsg3 () không hoạt động vì chúng tôi đặt nó trong dấu ngoặc kép mà không có bên nào nên nó được coi là một chuỗi.


Thể hiện các tình huống mà người hỏi hỏi về, nhưng không thực sự trả lời câu hỏi. Tôi không thấy những gì nó bổ sung qua các câu trả lời 6 năm hiện có .
Stephen P
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.