JavaScript มีการประเมิน "ลัดวงจร" หรือไม่


106

ฉันต้องการทราบว่า JavaScript มีการประเมิน "ลัดวงจร" เช่น && Operator ใน C # หรือไม่ ถ้าไม่ฉันต้องการทราบว่ามีวิธีแก้ปัญหาที่เหมาะสมในการนำไปใช้หรือไม่


2
ยินดีต้อนรับ ฉันได้เพิ่มhttps://www.google.com/search?q=site:stackoverflow.com+%sเป็นทางลัดการค้นหา (Chrome / Firefox) เพื่อเพิ่มความเร็วในการค้นหา
Rob W

นอกจากนี้ยังมีคำตอบสำหรับคำถามของฉันDeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GibboK

แหล่งข้อมูลที่มีประโยชน์เพิ่มเติม: The || คำถามการประเมินคำถาม &&
Samuel Hulla

คำตอบ:


123

ใช่ JavaScript มีการประเมินแบบ "ลัดวงจร"

if (true == true || foo.foo){
    // Passes, no errors because foo isn't defined.
}

การสาธิตสด

if (false && foo.foo){
    // Passes, no errors because foo isn't defined.
}

การสาธิตสด


9
ไฟฟ้าลัดวงจรจึงเป็นมาตรฐานใน JS?
GibboK

1
ขอบคุณ gdoron โปรดช่วยให้ฉันเข้าใจ ... ใน C # ฉันมีตัวดำเนินการไบนารีเช่นกันและตัวถูกดำเนินการทั้งสองต้องเป็นจริงเพื่อส่งผ่านแทนด้วย && ใน C
GibboK

1
@ GibboK. จากนั้นเห็นได้ชัดว่าไม่มีShort-circuitตัวดำเนินการตรรกะนั้น เพียงแค่ลองด้วยตัวคุณเอง ใช้การสาธิตของฉัน
gdoron สนับสนุน Monica

2
@GibboK: ดูการอ้างอิงตัวดำเนินการนี้ และใช่มีตัวดำเนินการไบนารี AND ใน JS เช่นกัน
Bergi

5
@ GibboK. ใช่ในมาตรฐาน! แต่ความคิดเห็นที่ดีเช่นเดียวกับในช่วงเวลาของการคอมไพล์มายากล JIT ในการใช้งานจาวาสคริปต์เราต้องการทราบว่ามีบางสิ่งเป็น "มาตรฐาน" หรืออาจเป็นไปตามการนำไปใช้งาน วิธีการบันทึกสภาพกับไบนารี Operators Logical คือการประเมินผลและ (สั้น Curcuit) เป็นพฤติกรรมมาตรฐานecma-international.org/ecma-262/5.1/#sec-11.11
humanityANDpeace

26

คำตอบนี้มีรายละเอียดมากเกี่ยวกับวิธีการ ทำงานใน JavaScript พร้อม gotcha ทั้งหมดและธีมที่เกี่ยวข้องเช่นลำดับความสำคัญของตัวดำเนินการหากคุณกำลังมองหาคำจำกัดความที่รวดเร็วและเข้าใจแล้วว่าการลัดวงจรทำงานอย่างไรฉันขอแนะนำให้ตรวจสอบคำตอบอื่น ๆ


สิ่งที่เรา (คิดว่าเรา) รู้จนถึงตอนนี้:

ก่อนอื่นให้ตรวจสอบพฤติกรรมที่เราทุกคนคุ้นเคยภายในif()บล็อกที่เราใช้&&ตรวจสอบว่าทั้งสองสิ่งคือtrue:

if (true && true) {
   console.log('bar');
} 

ตอนนี้สัญชาตญาณแรกของคุณอาจจะพูดว่า: 'อ่าใช่ค่อนข้างง่ายรหัสจะเรียกใช้คำสั่งถ้าทั้งคู่expr1และexpr2ได้รับการประเมินเป็นtrue'

ใช่และไม่ใช่ คุณเข้าใจถูกต้องในทางเทคนิคนั่นคือพฤติกรรมที่คุณอธิบายไว้แต่นั่นไม่ใช่วิธีการประเมินโค้ดอย่างแน่นอนและเราจะต้องเจาะลึกลงไปเพื่อที่จะเข้าใจอย่างถ่องแท้


มีการตีความ&&และ||ตีความอย่างไร:

ถึงเวลาดู "ภายใต้ฝากระโปรง เครื่องยนต์ "ลองพิจารณาตัวอย่างที่ใช้ได้จริงนี้:

function sanitise(x) {
  if (isNaN(x)) {
    return NaN;
  }
  return x;
}

let userinput = 0xFF; // as an example
const res = sanitise(userinput) && userinput + 5

console.log(res);

ผลก็คือ260.. แต่ทำไม? เพื่อให้ได้คำตอบเราต้องเข้าใจว่าการประเมินการลัดวงจรทำงานอย่างไร

โดยคำจำกัดความของ MDN ตัว&&ดำเนินการในexpr1 && expr2จะดำเนินการดังต่อไปนี้:

ถ้าexpr1สามารถแปลงเป็นtrueส่งคืนexpr2; expr1อื่นผลตอบแทน

ดังนั้นหมายความว่าในตัวอย่างการปฏิบัติของเราได้รับการconst resประเมินด้วยวิธีต่อไปนี้:

  1. การเรียกexpr1-sanitise(0xFF)
  2. 0xFF เป็นเลขฐานสิบหกที่ถูกต้องสำหรับ 250 มิฉะนั้นฉันจะส่งคืน NaN
  3. expr1กลับ "truthy" ค่าเวลาในการดำเนินการexpr2 (มิฉะนั้นผมจะหยุดNaNเป็น falsy)
  4. เนื่องจากuserinputเป็นความจริง (ตัวเลข) ฉันสามารถเพิ่ม+5เข้าไปได้
  • "ความจริง" หมายความว่านิพจน์สามารถประเมินได้ว่าเป็นจริง นี่คือรายการของ truthyและ falsy แสดงออก

ดังนั้นที่นี่เราจึงสามารถหลีกเลี่ยงการifบล็อกเพิ่มเติมและisNaNตรวจสอบเพิ่มเติมได้ด้วยการใช้งานตัว&&ดำเนินการง่ายๆ


มันทำงานอย่างไร:

ตอนนี้อย่างน้อยเราควรมีภาพว่าไฟล์ ผู้ประกอบการทำงาน กฎสากลดำเนินไป:

  • (some falsy expression) && expr จะประเมินว่าเป็นการแสดงออกที่ไม่ถูกต้อง
  • (some truthy expression) || expr จะประเมินเป็นการแสดงออกที่แท้จริง

นี่คือตัวอย่างเพิ่มเติมเพื่อความเข้าใจที่ดีขึ้น:

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() && b() ){
     console.log('foobar'); 
}

//Evaluates a() as false, stops execution.

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() || b() ){
     console.log('foobar'); 
}

/* 1. Evaluates a() as false
   2. So it should execute expr2, which is `b()`
   3. b() returned as true, executing statement `console.log('foobar');`
*/


สิ่งสุดท้ายที่น่ารำคาญ แต่สิ่งที่สำคัญมาก [Operator Precedence]:

ดีหวังว่าคุณจะได้รับมัน! สิ่งสุดท้ายที่เราต้องรู้คือกฎเกี่ยวกับลำดับความสำคัญของตัวดำเนินการนั่นคือ:

  • ตัว&&ดำเนินการจะถูกดำเนินการก่อนตัว||ดำเนินการเสมอ

พิจารณาตัวอย่างต่อไปนี้:

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log(a() || b() && c());

// returns a() and stops execution

a()นี้จะกลับมาเป็นบางทีอาจจะทำให้เกิดความสับสนในการบางอย่าง เหตุผลนั้นค่อนข้างง่ายเพียงแค่สายตาของเราที่หลอกลวงเราเพราะเราคุ้นเคยกับการอ่านจากซ้ายไปขวา ลองนำconsole.log()สิ่งที่ไม่ออกและมุ่งเน้นไปที่การประเมินผลอย่างแท้จริง

true || false && false

ตอนนี้ให้ห่อหัวของคุณรอบนี้:

  1. เรากล่าวว่าตัว&&ดำเนินการมีความสำคัญเหนือกว่าดังนั้นจึงได้รับการประเมินเป็นอันดับแรก เพื่อช่วยให้เราจินตนาการถึงการประเมินผลได้ดีขึ้นให้นึกถึงคำจำกัดความ

    expr1 && expr2
    

    ที่ไหน:

    • expr2 คือ false
    • expr1 คือ true || false
  2. นั่นเป็นส่วนที่ยุ่งยากตอนนี้true || falseได้รับการประเมินแล้ว ( expr1ด้านซ้ายของ&&)

    • กำหนดให้ตัว||ดำเนินการหยุดการดำเนินการหากexpr1 || expr2ในการexpr1ประเมินว่าเป็นจริงการexpr1ดำเนินการจะถูกดำเนินการและการเรียกใช้โค้ดจะหยุดลง
  3. ค่าที่ส่งคืนคือ true

นั่นค่อนข้างยุ่งยากทั้งหมดเป็นเพราะกฎและความหมายแปลก ๆ ไม่กี่ข้อ แต่จำไว้คุณก็สามารถหลบหนีความสำคัญกับผู้ประกอบการ()- เช่นเดียวกับในทางคณิตศาสตร์

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log((a() || b()) && c());

/* 1. The () escape && operator precedence
   2. a() is evaluated as false, so expr2 (c()) to be executed
   3. c()  
*/


ฉันจะ 1) ไม่ใช้คำว่า "คอมไพเลอร์" "เครื่องยนต์" มีความแม่นยำมากขึ้น 2) ไม่พูดถึงexpr1และexpr2 หรือcondition1หรืออะไรก็ตามที่เป็นเพียงความสับสน ตัดสินใจอย่างใดอย่างหนึ่งคุณสามารถแนะนำตัวแปรท้องถิ่นเช่น const expr1 = true; if(expr1 && ...)
Jonas Wilms

@JonasWilms ขอบคุณสำหรับการป้อนข้อมูลแก้ไขคำตอบตามนั้น
Samuel Hulla

1
สิ่งนี้ยังไม่ตอบคำถามที่ถามโดยตรง
Kevin B

7
นี่คือ"คำตอบที่ดีที่สุดที่ไม่ได้ตอบคำถามอย่างชัดเจน"ที่ฉันเคยเห็น ...
Gerardo Furtado

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