สิ่งก่อสร้าง x = x || y หมายถึงอะไร


250

ฉันกำลังแก้จุดบกพร่อง JavaScript บางส่วนและไม่สามารถอธิบายสิ่งนี้||ไม่?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

คนที่สามารถให้คำแนะนำฉันทำไมผู้ชายคนนี้คือการใช้var title = title || 'ERROR'? บางครั้งฉันเห็นมันโดยไม่มีการvarประกาศเช่นกัน


44
มีคนตอบแล้วนี้ ... แต่ต้องมากตระหนักถึงความจริงที่ว่าค่าที่สองที่ถูกเลือกถ้าค่าแรกคือไม่เพียงfalsy undefinedจำนวนครั้งที่ฉันได้เห็นdoWeDoIt = doWeDoIt || trueเพียงพอที่จะทำให้ฉันร้องไห้ (เช่นdoWeDoItตอนนี้จะไม่เป็นfalse)
แมตต์


4
สำหรับผู้ที่มีประสบการณ์กับ C #, ??ผู้ประกอบการดับเบิลท่อเทียบเท่ากับผู้ประกอบการด้วย Javascript ประเมินวัตถุที่ไม่เป็นโมฆะเช่น true (หรือ evalualtes ที่ดีกว่าวัตถุ null เป็นเท็จ)
usr-local-ΕΨΗΕΛΩΝ

3
อย่ารู้สึกแย่ - JS เป็นภาษาขำ ๆ เดียวที่อนุญาตให้เขียนโค้ดที่น่ากลัวนี้ .... และสอนว่ามันเหมาะสมในการซ้อนฟังก์ชั่นทุกอย่างลงในบรรทัดของรหัสและทิ้งมันทิ้งทำให้ไม่สามารถใช้งานได้เป็นครั้งที่สอง :) ฉันใช้เวลา 30 ปีในการเขียนโค้ดและหยุดยั้งการสัมผัส JS จนกระทั่งเมื่อไม่นานมานี้เองและฉันก็รู้สึกถึงความเจ็บปวดของคุณทั้งหมดที่ฉันสามารถพูดได้คือรักษา "ไม่มีเหตุผลมันเป็นแค่ใน JS" cheetsheet ได้รับโดย! :)
Collin Chaffin

1
โปรดพิจารณาเปลี่ยนคำตอบที่ได้รับการยอมรับในการคำตอบของฉัน
MichałPerłakowski

คำตอบ:


211

มันหมายถึงการtitleโต้แย้งเป็นตัวเลือก "Error"ดังนั้นถ้าคุณเรียกวิธีการที่มีการขัดแย้งใดก็จะใช้เป็นค่าเริ่มต้นของ

มันจดชวเลขสำหรับการเขียน:

if (!title) {
  title = "Error";
}

เคล็ดลับชวเลขและแบบนี้กับนิพจน์บูลีนเป็นเรื่องธรรมดาใน Perl เช่นกัน ด้วยการแสดงออก:

a OR b

มันประเมินtrueถ้าอย่างใดอย่างหนึ่งaหรือเป็นb trueดังนั้นหากaเป็นจริงคุณไม่จำเป็นต้องตรวจสอบbเลย สิ่งนี้เรียกว่าการประเมินบูลีนลัดวงจรดังนั้น:

var title = title || "Error";

โดยทั่วไปจะตรวจสอบว่าtitleประเมินfalseหรือไม่ ถ้ามันไม่ "ผลตอบแทน" มิฉะนั้นผลตอบแทน"Error"title


3
ขออภัยที่จะจู้จี้จุกจิก แต่อาร์กิวเมนต์ไม่ได้เป็นตัวเลือกการตรวจสอบข้อโต้แย้ง
themightybun

4
นี่ไม่ใช่คำตอบและฉันเห็นด้วยกับความคิดเห็นล่าสุดที่ไม่ได้เลือก ส่วนหนึ่งของคำตอบนี้ไม่ถูกต้องแม้แต่การอ้างอิง Perl เนื่องจากคำสั่ง Perl ทำให้ SENSE จริงและได้รับการประเมินด้วยวิธีที่แตกต่างอย่างสิ้นเชิง JS นั้นมีวิวัฒนาการในวิธีบูลีน "แปลง" ที่มากขึ้นซึ่งฉันก็พบว่าสับสนมากขึ้นในการอ่าน / เขียน คำตอบด้านล่างชื่อ "ผู้ดำเนินการไพพ์คู่คืออะไร" เป็นคำตอบที่ถูกต้อง
Collin Chaffin

198

ผู้ประกอบการท่อคู่ ( ||) คืออะไร?

ผู้ประกอบท่อคู่ ( ||) เป็นตรรกะที่ORผู้ประกอบการ ในภาษาส่วนใหญ่จะทำงานด้วยวิธีต่อไปนี้:

  • หากค่าแรกคือfalseมันจะตรวจสอบค่าที่สอง ถ้าเป็นtrueมันจะกลับมาtrueและถ้าเป็นfalseก็จะกลับfalseมา
  • ถ้าค่าแรกคือtrueมันจะคืนค่าเสมอtrueไม่ว่าค่าที่สองคืออะไร

ดังนั้นโดยทั่วไปมันใช้งานได้เหมือนฟังก์ชั่นนี้:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

หากคุณยังไม่เข้าใจให้ดูที่ตารางนี้:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

กล่าวอีกนัยหนึ่งมันเป็นเท็จเฉพาะเมื่อทั้งสองค่าเป็นเท็จ

JavaScript มีความแตกต่างกันอย่างไร

JavaScript เป็นที่แตกต่างกันเล็กน้อยเพราะมันเป็นภาษาพิมพ์อย่างอิสระ ในกรณีนี้หมายความว่าคุณสามารถใช้||โอเปอเรเตอร์ที่มีค่าที่ไม่ใช่บูลีน แม้ว่ามันจะไม่สมเหตุสมผล แต่คุณสามารถใช้โอเปอเรเตอร์นี้กับตัวอย่างฟังก์ชันและวัตถุ:

(function(){}) || {}

เกิดอะไรขึ้นที่นั่น

ถ้าค่าไม่ได้บูล, JavaScript ทำให้การแปลงนัยเพื่อบูล มันหมายความว่าถ้ามีค่าเป็น falsey (เช่น0, "", null, undefined(เห็นทุกค่า falsey ใน JavaScript )) ก็จะถือว่าเป็นfalse; trueมิฉะนั้นจะถือเป็น

ตัวอย่างด้านบนควรให้trueเพราะฟังก์ชันว่างคือความจริง ก็ไม่เป็นไร ส่งคืนฟังก์ชันว่าง นั่นเป็นเพราะ||ตัวดำเนินการของ JavaScript ไม่ทำงานอย่างที่ฉันเขียนไว้ตอนต้น มันทำงานวิธีดังต่อไปนี้:

  • ถ้าค่าแรกคือfalseyก็จะส่งกลับค่าที่สอง
  • ถ้าค่าแรกคือtruthyก็จะส่งกลับค่าแรก

ประหลาดใจ? อันที่จริงมันเป็น "เข้ากันได้" กับ||ผู้ประกอบการแบบดั้งเดิม มันสามารถเขียนได้เป็นฟังก์ชั่นดังต่อไปนี้:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

หากคุณผ่านค่าความจริงตามที่xมันส่งคืนxนั่นคือค่าความจริง ดังนั้นถ้าคุณใช้มันในภายหลังในifข้อ:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

"Either x or y is truthy."คุณจะได้รับ

ถ้าxเป็น falsey, จะเป็นeitherXorY yในกรณีนี้คุณจะได้รับ"Either x or y is truthy."ถ้าyเป็นจริง; "Neither x nor y is truthy"มิฉะนั้นคุณจะได้รับ

คำถามจริง

ตอนนี้เมื่อคุณรู้ว่า||ผู้ให้บริการทำงานอย่างไรคุณอาจทำเองได้ด้วยความx = x || yหมาย ถ้าxเป็นจริงxได้รับมอบหมายให้xดังนั้นจริง ๆ แล้วไม่มีอะไรเกิดขึ้น; มิฉะนั้นจะถูกกำหนดให้y xมันถูกใช้เพื่อกำหนดพารามิเตอร์เริ่มต้นในฟังก์ชั่น อย่างไรก็ตามมันมักจะถูกพิจารณาว่าเป็นแบบฝึกหัดการเขียนโปรแกรมที่ไม่ดีเพราะมันจะป้องกันคุณจากการผ่านค่าความผิดพลาด (ซึ่งไม่จำเป็นundefinedหรือnull) เป็นพารามิเตอร์ ลองพิจารณาตัวอย่างต่อไปนี้:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

มันดูถูกต้องตั้งแต่แรกเห็น แต่สิ่งที่จะเกิดขึ้นถ้าคุณผ่านการfalseเป็นflagAพารามิเตอร์ (ตั้งแต่มันบูลคือสามารถtrueหรือfalse)? มันจะกลายเป็น trueในตัวอย่างนี้มีวิธีการตั้งไม่มีการflagAfalse

มันจะเป็นความคิดที่ดีกว่าเพื่อตรวจสอบอย่างชัดเจนว่าflagAเป็นundefinedเช่นนั้น:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

แม้ว่าจะใช้เวลานาน แต่ก็ใช้งานได้และเข้าใจง่ายกว่า


คุณยังสามารถใช้ไวยากรณ์ ES6 สำหรับพารามิเตอร์ฟังก์ชั่นเริ่มต้นได้ แต่โปรดทราบว่ามันจะไม่ทำงานในเบราว์เซอร์รุ่นเก่า (เช่น IE) หากคุณต้องการที่จะสนับสนุนเบราว์เซอร์เหล่านี้คุณควร transpile รหัสของคุณกับบาเบล

ดูเพิ่มเติมOperators Logical บน MDN


13
+1 - โดยคำตอบที่ถูกต้องและครบถ้วนที่สุด และสำหรับผู้ที่มีคำถามนี้ (เราบางคนมีประสบการณ์ใช้รหัสใหม่รวมถึง JS) ควรเน้นคำตอบที่ดีที่สุดในบรรทัดนี้: "แม้ว่ามันจะไม่สมเหตุสมผล" เพราะ "loosley ที่พิมพ์" นี้จะไม่มีเหตุผล สำหรับพวกเราที่เติบโตขึ้นมาโดยปราศจากมัน สำหรับเราแล้วโอเปอเรเตอร์บูลีนเป็นเพียงแค่นั้นและเท่านั้นที่ ...... และใครก็ตามที่เคยคิดว่ามันจะเป็นความคิดที่ดีที่จะต้องหยุดและคิดผ่านการแปลงที่แปลกประหลาดของค่าที่ไม่บูลีนเป็นบูลีนในขณะที่อ่าน / เขียนรหัส ลืมที่จะใช้ยาของพวกเขาในวันนั้น! :)
Collin Chaffin

2
+1 สั้น ๆ : title = title || 'Error'หมายถึงif (title) { title = title; } else { title = 'Error'; }
Andre Elrico

ฉันไม่เห็นด้วยกับบรรทัด "แม้ว่าจะไม่สมเหตุสมผล" ฉันเข้าใจว่าบรรทัดจะไม่คอมไพล์ใน C ตัวอย่างเช่น แต่มันเข้าใจได้ดีถ้าคุณมาจาก Ruby หรือแม้แต่ Groovy title ||= 'Error'ในทับทิมคุณสามารถแสดงมันแม้สั้นเช่น
Elliot Nelson

28

หากไม่ได้ตั้งชื่อให้ใช้ 'ข้อผิดพลาด' เป็นค่าเริ่มต้น

ทั่วไปเพิ่มเติม:

var foobar = foo || default;

อ่าน: ชุด foobar ไปหรือfoo defaultคุณสามารถเชื่อมโยงสิ่งนี้ได้หลายครั้ง:

var foobar = foo || bar || something || 42;

1
ฉันพบว่ามันสับสนเพราะตัวแปรมีชื่อเหมือนกัน ง่ายกว่าเมื่อไม่ทำ
Norbert Norbertson

14

อธิบายเรื่องนี้อีกเล็กน้อย ...

||ประกอบเป็นตรรกะorประกอบการ ผลลัพธ์จะเป็นจริงถ้าส่วนแรกเป็นจริงและเป็นจริงถ้าส่วนที่สองเป็นจริงและเป็นจริงถ้าทั้งสองส่วนเป็นจริง เพื่อความชัดเจนนี่คือตาราง:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

ตอนนี้สังเกตเห็นบางสิ่งที่นี่? หากXเป็นจริงผลลัพธ์จะเป็นจริงเสมอ ดังนั้นหากเรารู้ว่าXเป็นความจริงเราไม่ต้องตรวจสอบYเลย หลายภาษาใช้เครื่องมือประเมิน "ลัดวงจร" สำหรับตรรกะ - or(และตรรกะ - andมาจากทิศทางอื่น) พวกเขาตรวจสอบองค์ประกอบแรกและถ้าเป็นจริงพวกเขาไม่ได้ตรวจสอบองค์ประกอบที่สองเลย ผลลัพธ์ (ในแง่ตรรกะ) เหมือนกัน แต่ในแง่ของการดำเนินการอาจมีความแตกต่างกันอย่างมากหากองค์ประกอบที่สองมีราคาแพงในการคำนวณ

ดังนั้นสิ่งนี้เกี่ยวข้องกับตัวอย่างของคุณ?

var title   = title || 'Error';

ลองดูที่ titleองค์ประกอบถูกส่งผ่านไปในการทำงานของคุณ ใน JavaScript หากคุณไม่ผ่านพารามิเตอร์ก็จะมีค่าเริ่มต้นเป็นค่าว่าง นอกจากนี้ใน JavaScript หากตัวแปรของคุณเป็นค่า Null ก็ถือว่าเป็นเท็จโดยตัวดำเนินการเชิงตรรกะ ดังนั้นถ้าฟังก์ชั่นนี้ถูกเรียกด้วยชื่อที่กำหนดมันเป็นค่าที่ไม่เป็นเท็จและกำหนดให้กับตัวแปรท้องถิ่น อย่างไรก็ตามถ้ามันไม่ได้รับค่ามันเป็นค่า Null และดังนั้นจึงเป็นเท็จ ตัวorดำเนินการเชิงตรรกะจะประเมินนิพจน์ที่สองและส่งกลับ 'ข้อผิดพลาด' แทน ดังนั้นตอนนี้ตัวแปรท้องถิ่นจะได้รับค่า 'ข้อผิดพลาด'

สิ่งนี้ทำงานได้เนื่องจากการใช้งานของการแสดงออกตรรกะใน JavaScript มันไม่ได้กลับมาเป็นค่าบูลีนที่เหมาะสม ( trueหรือfalse) แต่แทนที่จะส่งกลับค่าที่ได้รับภายใต้กฎระเบียบบางอย่างเป็นสิ่งที่ถือว่าเทียบเท่ากับและสิ่งที่ถือว่าเทียบเท่ากับtrue falseค้นหาการอ้างอิง JavaScript ของคุณเพื่อเรียนรู้ว่า JavaScript ถือว่าเป็นจริงหรือเท็จในบริบทบูลีน


8

ไปป์คู่หมายถึงตรรกะ "หรือ" นี่ไม่ใช่กรณีเมื่อ "พารามิเตอร์ไม่ได้ตั้งค่า" เนื่องจากในจาวาสคริปต์อย่างเคร่งครัดหากคุณมีรหัสเช่นนี้:

function foo(par) {
}

จากนั้นโทร

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

ไม่เทียบเท่า

Double pipe (||) จะใช้อาร์กิวเมนต์ตัวแรกในการบูลีนและถ้าบูลีนที่ได้นั้นเป็นความจริง

สิ่งนี้สำคัญถ้าคุณตรวจสอบพารามิเตอร์ที่ไม่ได้ตั้งค่า

สมมติว่าเรามีฟังก์ชั่น setSalary ที่มีพารามิเตอร์ทางเลือกเดียว หากผู้ใช้ไม่ได้ระบุพารามิเตอร์ดังนั้นควรใช้ค่าดีฟอลต์ 10

ถ้าคุณทำเครื่องหมายเช่นนี้:

function setSalary(dollars) {
    salary = dollars || 10
}

สิ่งนี้จะให้ผลลัพธ์ที่ไม่คาดคิดเช่นการโทร

setSalary(0) 

มันจะยังคงตั้งค่า 10 ตามการไหลที่อธิบายไว้ข้างต้น


8

โดยทั่วไปจะตรวจสอบว่าค่าก่อน | | หาค่าเป็นจริงถ้าใช่ใช้ค่านี้ถ้าไม่ใช้ก็จะใช้ค่าหลังจาก ||

ค่าที่จะรับค่าหลังจาก || (เท่าที่ฉันจำได้):

  • ไม่ได้กำหนด
  • เท็จ
  • 0
  • '' (สตริง Null หรือ Null)

1
false || null || ไม่ได้กำหนด || 0 || '' || 'คุณลืมโมฆะ'
Dziamid

7

ในขณะที่คำตอบของ Cletusนั้นถูกต้องฉันรู้สึกว่าควรเพิ่มรายละเอียดเพิ่มเติมเกี่ยวกับ "ประเมินเป็นเท็จ" ใน JavaScript

var title = title || 'Error';
var msg   = msg || 'Error on Request';

ไม่ได้เป็นเพียงการตรวจสอบว่าชื่อ / ผงชูรสได้รับการให้บริการ แต่ยังถ้าอย่างใดอย่างหนึ่งของพวกเขาเป็นfalsy คือหนึ่งในสิ่งต่อไปนี้:

  • เท็จ
  • 0 (ศูนย์)
  • "" (สตริงว่าง)
  • โมฆะ
  • ไม่ได้กำหนด.
  • NaN (ค่าตัวเลขพิเศษหมายถึง Not-a-Number!)

ดังนั้นในสาย

var title = title || 'Error';

หากชื่อเรื่องเป็นความจริง (เช่นไม่ใช่เท็จดังนั้นชื่อ = "titleMessage" ฯลฯ ) จากนั้นผู้ประกอบการบูลีนหรือ (| |) พบค่าหนึ่งที่ 'จริง' ซึ่งหมายความว่าจะประเมินเป็นจริงดังนั้นจึงเป็นวงจรสั้นและส่งกลับ มูลค่าที่แท้จริง (ชื่อเรื่อง)

หากชื่อเป็นเท็จ (เช่นหนึ่งในรายการด้านบน) ผู้ประกอบการบูลีน OR (||) พบค่า 'เท็จ' และตอนนี้ต้องประเมินส่วนอื่น ๆ ของตัวดำเนินการ 'ข้อผิดพลาด' ซึ่งประเมินว่าเป็นจริง และจะถูกส่งกลับดังนั้น

ดูเหมือนว่า (หลังจากการทดลองใช้ firebug console อย่างรวดเร็ว) หากทั้งสองด้านของผู้ประกอบการประเมินว่าเป็นเท็จจะส่งคืนตัวดำเนินการ 'falsy' ตัวที่สอง

กล่าวคือ

return ("" || undefined)

ส่งคืนค่าที่ไม่ได้กำหนดนี่เป็นโอกาสที่คุณจะสามารถใช้พฤติกรรมที่ถามถึงในคำถามนี้เมื่อพยายามที่จะตั้งชื่อ / ข้อความเริ่มต้นเป็น "" นั่นคือหลังจากที่ทำงาน

var foo = undefined
foo = foo || ""

foo จะถูกตั้งค่าเป็น ""


5

ผู้ประกอบการท่อคู่

ตัวอย่างนี้มีประโยชน์หรือไม่

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

ยังสามารถ

var section = document.getElementById('special') || document.getElementById('main');

4

เพื่อเพิ่มคำอธิบายให้ทุกคนพูดก่อนหน้าฉันควรให้ตัวอย่างบางอย่างแก่คุณเพื่อให้เข้าใจแนวคิดเชิงตรรกะ

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

หมายความว่าหากด้านซ้ายประเมินว่าเป็นข้อความจริงมันจะเสร็จสิ้นและด้านซ้ายจะถูกส่งคืนและกำหนดให้กับตัวแปร ในกรณีอื่นทางด้านขวาจะถูกส่งคืนและกำหนด

และผู้ประกอบการมีโครงสร้างตรงข้ามเช่นด้านล่าง

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh

3

|| เป็นผู้ประกอบการบูลีนหรือ เช่นเดียวกับใน javascript, undefined, null, 0, falseถือเป็นค่าเท็จ

มันหมายถึง

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"

2

ข้อความอ้างอิง: "โครงสร้าง x = x || y หมายถึงอะไร"

การกำหนดค่าเริ่มต้น

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


นั่นคือความหมายที่แท้จริงของโครงสร้างและความหมายเดียวของมัน และมันก็เป็นรูทีนย่อยอย่างมากมายในการเขียนฟังก์ชั่นที่สามารถเรียกได้ว่าเป็นต้นแบบ, ฟังก์ชั่นแบบสแตนด์อโลนและยังเป็นวิธีการยืมเพื่อนำไปใช้กับองค์ประกอบอื่น ในกรณีที่หน้าที่หลักและหน้าที่เดียวคือแก้ไขการอ้างอิงเป้าหมาย ตัวอย่าง: function getKeys(x) { x = x || this ; .... }ซึ่งสามารถใช้โดยไม่มีการดัดแปลงเป็นฟังก์ชันแบบสแตนด์อโลนเป็นวิธีการคุณสมบัติในแบบตัวอย่างและเป็นวิธีการขององค์ประกอบที่สามารถรับองค์ประกอบอื่นเป็นอาร์กิวเมนต์ของมันเป็น `[องค์ประกอบ] .getKeys (anotherElement); '
Bekim Bacaj

-5

และฉันต้องเพิ่มอีกหนึ่งอย่าง: ชวเลขเล็กน้อยนี้เป็นสิ่งที่น่ารังเกียจ เป็นการเพิ่มประสิทธิภาพล่ามโดยไม่ตั้งใจ (ไม่รบกวนการปฏิบัติงานที่สองหากครั้งแรกเป็นความจริง) เพื่อควบคุมการมอบหมาย การใช้งานนั้นไม่เกี่ยวข้องกับวัตถุประสงค์ของผู้ปฏิบัติงาน ฉันไม่เชื่อว่ามันควรจะใช้

ฉันชอบผู้ประกอบการที่สามสำหรับการเริ่มต้นเช่น

var title = title?title:'Error';

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

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