ความแตกต่างระหว่าง setTimeout ทั้งที่มีและไม่มีเครื่องหมายคำพูดและวงเล็บ


240

ฉันกำลังเรียนรู้ JavaScript และฉันได้เรียนรู้เมื่อเร็ว ๆ นี้เกี่ยวกับเหตุการณ์กำหนดเวลา JavaScript เมื่อฉันเรียนรู้setTimeoutที่W3Schoolsฉันสังเกตเห็นรูปแปลก ๆ ที่ฉันไม่เคยพบเจอมาก่อน พวกเขากำลังใช้เครื่องหมายคำพูดคู่แล้วเรียกใช้ฟังก์ชัน

ตัวอย่าง:

setTimeout("alertMsg()", 3000);

ฉันรู้ว่าอัญประกาศคู่และเดี่ยวใน JavaScript หมายถึงสตริง

นอกจากนี้ฉันเห็นว่าฉันสามารถทำเช่นเดียวกัน:

setTimeout(alertMsg, 3000);

ด้วยวงเล็บมันคือการอ้างอิงโดยไม่ต้องวงเล็บมันคัดลอก เมื่อฉันใช้คำพูดและวงเล็บมันเริ่มบ้า

ฉันจะดีใจถ้ามีคนอธิบายให้ฉันฟังถึงความแตกต่างระหว่างการใช้ทั้งสามวิธีsetTimeout:

ด้วยวงเล็บ:

setTimeout("alertMsg()", 3000);

ไม่มีเครื่องหมายคำพูดและวงเล็บ:

setTimeout(alertMsg, 3000);

และอันที่สามใช้คำพูดเท่านั้น:

setTimeout("alertMsg", 3000);

หมายเหตุ: เป็นแหล่งที่ดีกว่าสำหรับsetTimeoutการอ้างอิงจะMDN


5
@Jefffrey ว่าเว็บไซต์ w3fools ไม่ได้บอกว่ามีเนื้อหาผิดปกติเพียงเพราะมันอาจล้าสมัยและขาดสิ่งใหม่ ๆ ควรปรับใช้เป็นข้อมูลอ้างอิงสำหรับ (หรือเพื่อเรียนรู้) เนื้อหาหลัก ฉันสามารถเข้าใจผู้คนที่รู้สึกผิดหวังโดยวิธีที่พวกเขาพยายามดูเหมือนว่าพวกเขาเป็นส่วนหนึ่งของ w3 แต่นั่นไม่ได้เบี่ยงเบนความสนใจจากเนื้อหา มันวางไว้อย่างดีและง่ายต่อการอ่านด้วยตัวอย่างที่ชัดเจนนายอำเภอสำหรับ noobs
Matthew

14
@ Matewew "เรารู้สึกว่า W3Schools กำลังทำร้ายชุมชนด้วยข้อมูลที่ไม่ถูกต้อง" - ภายในสามบรรทัดแรก
รองเท้า

1
@Jefffrey ใช่ฉันเห็นว่า แต่ลดระดับลงที่พวกเขาอธิบายสิ่งที่พวกเขาไม่ชอบเกี่ยวกับเรื่องนี้ในส่วน "W3Schools is problems" ไม่มีเหตุผลสามประการที่พวกเขาให้อะไรเกี่ยวกับข้อมูลที่ไม่ถูกต้อง พวกเขาไม่มีตัวอย่างเดียวของสิ่งใดที่เป็นจริง "ผิด" ข้อร้องเรียนของพวกเขาคือพวกเขาไม่ได้บอกชัดเจนว่าพวกเขาไม่ได้มีส่วนเกี่ยวข้องกับ w3 พวกเขาเรียกเก็บเงินสำหรับการรับรองที่ไม่รู้จักและพวกเขาไม่ได้อัปเดตอย่างรวดเร็วด้วยเนื้อหาใหม่ (เช่น html 5)
Matthew

10
@ Matewew, ข้อมูลที่ล้าสมัย, ในภาษาที่ละเอียดอ่อนเช่น Javascript, SQL หรือ PHP, เป็นสิ่งที่ชี้แนะนักเขียนโปรแกรมที่ต้องการติดเทคโนโลยีเก่าและอันตราย (เช่นmysql_ส่วนขยายของ PHP) ซึ่งกระแสคำถาม SO เป็นเพียงตัวอย่าง IIRC มีข้อผิดพลาดที่ละเอียดอ่อนบางอย่างในส่วนของ SQL เช่นกัน แต่ก็เกือบปีแล้วตั้งแต่ครั้งล่าสุดที่ฉันได้เยี่ยมชมเว็บไซต์และอาจแก้ไขได้จำนวนมาก และแม้ว่าทั้งหมดข้างต้นจะสมบูรณ์แบบฉันก็ยังคงไม่ส่งเสริมเว็บไซต์ที่พยายามหลอกลวงผู้คนด้วยการฉ้อโกงใบรับรองของพวกเขา
รองเท้า

4
การรับรองที่ร่มรื่นเป็นแหล่งข้อมูลอ้างอิงที่ดีและต่อต้านผลกระทบทั้งหมดของ SO เพื่อที่จะประณามพวกเขา
พุธที่

คำตอบ:


382

ใช้setIntervalหรือsetTimeout

คุณควรจะผ่านการอ้างอิงถึงฟังก์ชั่นเป็นอาร์กิวเมนต์แรกสำหรับหรือsetTimeout setIntervalเอกสารอ้างอิงนี้อาจอยู่ในรูปแบบของ:

  • ฟังก์ชั่นที่ไม่ระบุชื่อ

    setTimeout(function(){/* Look mah! No name! */},2000);
  • ชื่อของฟังก์ชั่นที่มีอยู่

    function foo(){...}
    
    setTimeout(foo, 2000);
    
  • ตัวแปรที่ชี้ไปยังฟังก์ชันที่มีอยู่

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

    โปรดทราบว่าฉันตั้ง "ตัวแปรในฟังก์ชั่น" แยกต่างหากจาก "ชื่อฟังก์ชั่น" ไม่ชัดเจนว่าตัวแปรและชื่อฟังก์ชั่นครอบครองเนมสเปซเดียวกันและสามารถบดบังซึ่งกันและกัน

ผ่านข้อโต้แย้ง

ในการเรียกใช้ฟังก์ชันและพารามิเตอร์ส่งผ่านคุณสามารถเรียกใช้ฟังก์ชันภายในการเรียกกลับที่กำหนดให้กับตัวจับเวลา:

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

มีวิธีการที่จะผ่านในการขัดแย้งเข้าไปจัดการอื่นเป็น แต่มันไม่ได้เป็นเบราว์เซอร์ที่รองรับ

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

บริบทการโทรกลับ

โดยค่าเริ่มต้นบริบทของการเรียกกลับ (ค่าของthisภายในฟังก์ชั่นที่เรียกว่าโดยจับเวลา) windowเมื่อดำเนินการเป็นวัตถุที่ทั่วโลก bindถ้าคุณต้องการที่จะเปลี่ยนการใช้งาน

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

ความปลอดภัย

แม้ว่ามันจะเป็นไปได้คุณควรไม่ผ่านสตริงไปหรือsetTimeout setIntervalการส่งสตริงทำให้setTimeout()หรือsetInterval()ใช้ฟังก์ชันที่คล้ายกับeval()ที่เรียกใช้สตริงเป็นสคริปต์ทำให้สามารถดำเนินการกับสคริปต์ได้เองและเป็นอันตราย


ฉันได้เรียนรู้ว่าเมื่อคุณใช้เพียงชื่อฟังก์ชั่นฟังก์ชั่นจะถูกคัดลอกดังนั้นทำไมคุณถึงพูดในตัวอย่างแรกของคุณว่า setTumeout foo (ฟังก์ชั่น) ผ่านการอ้างอิงฟังก์ชั่นที่ฉันได้เอนกายถูกคัดลอก และคุณสามารถทำให้ฉันสูงขึ้นได้โปรดเกี่ยวกับความกรุณาด้วย
user1316123

41
ฟังก์ชัน @ user1316123 จะไม่ถูกคัดลอก เหมือนกันกับวัตถุและอาร์เรย์ พวกเขาจะผ่านอ้างอิง คุณควรหยุดอ่าน w3schools พวกเขาทำอันตรายมากกว่าดี
โยเซฟ

4
ฟังก์ชัน @JosephtheDreamer เป็นวัตถุ "ชื่อฟังก์ชั่น" และ "ตัวแปรที่อ้างถึงฟังก์ชั่น" เป็นสิ่งเดียวกัน นอกจากนี้คุณสามารถส่งพารามิเตอร์ไปยัง setTimeout ได้โดยตรง (ไม่จำเป็นต้องล้อมแลมบ์ดาไว้ (แม้ว่าคุณจะบอกว่า - เบราว์เซอร์ที่ใหม่กว่า) นอกจากนี้ปัญหาไม่ได้เกิดจากการอนุญาตให้ผู้ใช้เรียกใช้สคริปต์ ก็โดยการยอมรับการป้อนข้อมูลจากอื่น ๆผู้ใช้และการทำงานที่เป็นสคริปต์ผู้ใช้เองสามารถเสมอเพียงเปิดคอนโซลและดำเนินการโดยพล JavaScript..
เบนจามิน Gruenbaum

@BenjaminGruenbaum ฉันกำลังจะพูดถึงประโยคที่สองของคุณเกือบจะเหมือนกัน หัวเราะ :)
ริ

2
ฉันไม่ทราบว่าคุณจำเป็นต้องใช้ฟังก์ชั่นเพื่อให้ setTimeout ทำงานได้อย่างถูกต้อง ขอบคุณที่ล้างข้อมูล
แมตต์เดลล์

3

ฉันคิดว่าฟังก์ชั่น setTimeout ที่คุณเขียนไม่ได้ทำงานอยู่ ถ้าคุณใช้ jquery คุณสามารถทำให้มันทำงานอย่างถูกต้องโดยทำสิ่งนี้:

    function alertMsg() {
      //your func
    }

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

ฉัน thinkink เช่นเดียวกับคุณ แต่การเชื่อมโยงw3schools.com/js/js_timing.aspบอก somting อื่น
user1316123

ถ้าฉันเข้าใจถูกต้องเมื่อฉันใช้วงเล็บฉันสามารถอ้างอิงเฉพาะฟังก์ชั่นที่มีวิธีการ setTimeout เพราะฟังก์ชั่นที่มีอยู่ที่วงเล็บเฉพาะที่มันขอบเขตท้องถิ่น?
user1316123

2

เห็นด้วยกับโจเซฟโดยสิ้นเชิง

นี่คือซอที่จะทดสอบสิ่งนี้: http://jsfiddle.net/nicocube/63s2s/

ในบริบทของซอ, อาร์กิวเมนต์สตริงไม่ทำงานในความคิดของฉันเพราะฟังก์ชั่นไม่ได้กำหนดไว้ในขอบเขตทั่วโลก


w3schools.com/js/js_timing.aspถ้าคุณสามารถเข้าลิงค์โปรดและเห็น becouse โจเซฟบอกว่ามันอันตราย แต่ถ้าคุณใส่ลิงค์มันใช้งานได้
user1316123

พวกโปรดดูที่นี่: quirksmode.org/js/this.htmlลิงก์นี้บอกว่าสามารถคัดลอก func ได้
user1316123

ใช่มันสามารถเพราะฟังก์ชั่นเป็นวัตถุใน JS ปัญหาเกี่ยวกับการใช้ eval ก็คือมันจะถูกประเมินในบริบทของโลกและไม่สามารถรับบริบทในท้องถิ่นที่เกิดขึ้นได้
Nicocube

คุณช่วยอธิบายด้วยคำบางคำได้มั้ย
user1316123

คำอธิบายที่ดี: javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval
Nicocube

1

เกิดอะไรขึ้นในความเป็นจริงในกรณีที่คุณส่งสตริงเป็นพารามิเตอร์แรกของฟังก์ชัน

setTimeout ( 'string', number)

คือค่าของพารามิเตอร์แรกที่ได้รับการประเมินเมื่อถึงเวลาที่ต้องเรียกใช้ (หลังจากnumberผ่านไปหนึ่งในพันของวินาที) โดยทั่วไปจะเท่ากับ

setTimeout ( eval('string'), number)

นี่คือ

ไวยากรณ์ทางเลือกที่ช่วยให้คุณสามารถรวมสตริงแทนฟังก์ชั่นซึ่งรวบรวมและดำเนินการเมื่อหมดเวลา ไม่แนะนำให้ใช้ไวยากรณ์นี้ด้วยเหตุผลเดียวกันกับที่ทำให้การใช้ eval () มีความเสี่ยงด้านความปลอดภัย

ดังนั้นตัวอย่างที่คุณอ้างถึงไม่ใช่ตัวอย่างที่ดีและอาจได้รับในบริบทที่แตกต่างกันหรือพิมพ์ผิดธรรมดา

ถ้าคุณเรียกเช่นนี้setTimeout(something, number)พารามิเตอร์แรกไม่สตริง somethingแต่ชี้ไปยังบางสิ่งบางอย่างที่เรียกว่า และอีกครั้งถ้าsomethingเป็นสตริง - แล้วมันจะถูกประเมิน แต่ถ้ามันเป็นฟังก์ชั่นแล้วฟังก์ชั่นจะถูกดำเนินการ ตัวอย่าง 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

ด้วยวงเล็บ:

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

ไม่มีเครื่องหมายคำพูดและวงเล็บ:

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

และอันที่สามใช้คำพูดเท่านั้น:

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);

ในตัวอย่างข้างต้นก่อน alertMsg2 () ฟังก์ชั่นการโทรทันที (เราให้เวลาหมด 4S แต่มันไม่ได้รบกวน) หลังจาก alertMsg1 () (รอเวลา 2 วินาที) จากนั้น alertMsg4 () รอเวลา 8 วินาที) แต่ alertMsg3 () ไม่ทำงานเพราะเราวางไว้ในเครื่องหมายคำพูดโดยไม่มีฝ่ายดังนั้นมันจะถือว่าเป็นสตริง


แสดงให้เห็นถึงสถานการณ์ที่ผู้ถามถาม แต่ไม่ได้ตอบคำถาม ฉันไม่เห็นสิ่งนี้จะเพิ่มคำตอบที่มีอายุ 6 ปีที่มีอยู่
Stephen P
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.