JS Boolean มีคุณสมบัติที่กำหนดเองเป็นแนวปฏิบัติที่ไม่ดีหรือไม่?


41

ใน JS คุณสามารถส่งคืนบูลีนที่มีคุณสมบัติแบบกำหนดเองได้ เช่น. เมื่อ Modernizr ทดสอบการรองรับวิดีโอจะส่งคืนtrueหรือfalseแต่ Boolean ที่ส่งคืน (Bool เป็นออบเจ็กต์ชั้นหนึ่งใน JS) มีคุณสมบัติที่ระบุรูปแบบที่สนับสนุน ตอนแรกมันทำให้ฉันประหลาดใจนิดหน่อย แต่จากนั้นฉันก็เริ่มชอบความคิดและเริ่มสงสัยว่าทำไมมันถึงถูกใช้อย่าง จำกัด

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

มีข้อโต้แย้ง 3 ข้อที่ฉันสามารถจินตนาการได้:

  1. มันค่อนข้างแปลก / คาดไม่ถึงเมื่อมันน่าจะดีกว่าสำหรับอินเทอร์เฟซใด ๆ ที่จะชัดเจนและไม่ยุ่งยาก
  2. นี่อาจเป็นอาร์กิวเมนต์คนฟาง แต่เป็นกรณีเล็กน้อยฉันสามารถจินตนาการมัน backfires เงียบ ๆ ใน JS optimizer, uglifier, VM หรือหลังจากการเปลี่ยนแปลงข้อกำหนดภาษาเล็กน้อยทำความสะอาด ฯลฯ
  3. มีวิธีที่ดีกว่ากระชับชัดเจนและเหมือนกันทุกประการ

ดังนั้นคำถามของฉันคือมีเหตุผลใดที่ควรหลีกเลี่ยงการใช้ Booleans ด้วยคุณสมบัติเพิ่มเติมหรือไม่ พวกเขาเป็นกลอุบายหรือการรักษา?


แผนบิดเตือน

ข้างต้นเป็นคำถามเดิมในเกียรติศักดิ์เต็ม ในฐานะที่เป็น Matthew Crumley และ Senevoldsen ทั้งคู่ชี้ว่ามันมีพื้นฐานมาจากหลักฐานเท็จ (เท็จ)? ในประเพณี JS ที่ดีสิ่งที่ Modernizr ทำคือการใช้ภาษาและสิ่งสกปรก มันเดือดลงมาที่ JS ที่มีบูลดั้งเดิมซึ่งหากตั้งค่าเป็นเท็จจะยังคงเป็นเท็จแม้หลังจากพยายามที่จะเพิ่มอุปกรณ์ประกอบฉาก (ซึ่งล้มเหลวอย่างเงียบ ๆ ) และวัตถุบูลีนที่สามารถมีอุปกรณ์ประกอบฉากที่กำหนดเองได้ Modernizr ส่งคืนบูลีน false หรือวัตถุบูลีนจริง

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


35
ขยายประเภทบูลเป็นคลาสสิกWTF
hlovdal

7
โปรดทราบว่าใน JS พวกเขาสามารถส่งคืนnullได้หากไม่ได้รับการสนับสนุนและอาร์เรย์ของรูปแบบถ้าเป็นเช่นนั้น รายการถือว่าเป็นความจริงใน JS และnullเป็นเท็จ
jpmc26


3
ก่อนที่คุณจะตอบคำถามนี้: ใน javascript มีความแตกต่างอย่างมากระหว่าง "บูลีน" และ "บูลีน" พวกเขาไม่เหมือนกันและคำตอบใด ๆ ที่ไม่ได้ใช้ประโยชน์จากบูลีนนั้นไม่ถูกต้อง
Pieter B

2
สำหรับพวกคุณที่ตกตะลึงที่จะเห็นอะไรแบบนี้ในป่าในห้องสมุดที่ได้รับความนิยมเช่น Modernizr นี่คือรหัสที่เกี่ยวข้องจาก GitHub ของพวกเขา: github.com/Modernizr/Modernizr/blob/ ......
Chris Nielsen

คำตอบ:


38

นอกเหนือจากหลักการออกแบบทั่วไปเช่นความรับผิดชอบเดี่ยวและความประหลาดใจน้อยที่สุดแล้วยังมีเหตุผลเฉพาะ JavaScript ที่ไม่ใช่ความคิดที่ดี: มีความแตกต่างอย่างมากระหว่างbooleanและBooleanใน JavaScript ที่ป้องกันไม่ให้ทำงานในกรณีทั่วไป

booleanเป็นชนิดดั้งเดิมไม่ใช่วัตถุและไม่สามารถมีคุณสมบัติที่กำหนดเองได้ การแสดงออกเช่นการทำงานเพราะเบื้องหลังมันจะกลายเป็นtrue.toString()(new Boolean(true)).toString()

Boolean(มีตัวอักษรตัวใหญ่ B) เป็นวัตถุ แต่มีประโยชน์น้อยมากและใช้เป็นแบบbooleanไม่แน่นอนอย่างใดอย่างหนึ่ง เหตุผลก็คือว่าทุกคนBooleanเป็น "จริง" โดยไม่คำนึงถึงคุณค่าของมันเพราะวัตถุทั้งหมดได้รับการแปลงtrueเป็นบริบทบูลีน ตัวอย่างเช่นลองสิ่งนี้:

var answer = new Boolean(false);
if (answer) {
  console.log("That was unexpected.");
}

โดยทั่วไปแล้วไม่มีทางที่จะเพิ่มคุณสมบัติให้กับบูลีนใน JavaScript ที่ยังคงให้มันทำงานในลักษณะตรรกะ Modernizr สามารถหนีไปได้เพราะมันเพิ่มคุณสมบัติให้กับค่า "true" เท่านั้นซึ่งเป็นประเภทงานที่คุณคาดหวัง (เช่นทำงานใน if statement) หากวิดีโอไม่ได้รับการสนับสนุนเลยModernizr.videoจะเป็นของจริงboolean(มีค่าfalse) และไม่สามารถเพิ่มคุณสมบัติได้


18
ฉันพบว่าแนวทางของ Modernizr ค่อนข้างแปลกเมื่อพิจารณาว่าการมีเพียงวัตถุที่มีคุณสมบัติประเมินtrueอยู่ในเงื่อนไขแล้ว ทำไมต้องใช้ a Boolean?
Arturo Torres Sánchez

ขอบคุณมากสำหรับข้อโต้แย้งทางเทคนิคเสียง ดูเหมือนว่าการทดสอบอย่างรวดเร็วของฉันมีข้อบกพร่อง: jsbin.com/hurebi/3/edit?js,console แม้หลังจากเพิ่มอุปกรณ์ประกอบฉากที่กำหนดเองลงไปfalseแล้วมันก็ 'เท็จ' และเท็จ ( ===และ==ทำงานเป็น) อย่างเคร่งครัดแต่จริงๆแล้วคุณไม่สามารถเพิ่มอุปกรณ์ประกอบฉากให้กับบูลดั้งเดิมได้ ความแตกต่างระหว่างบูลและบูลก็ทำให้ฉันหนีจากไป
Konrad

@ ArturoTorresSánchezเพราะวิธีที่พวกเขาทำมันกลับมาเป็นค่าในนามของประเภทเดียวกัน
Jared Smith

1
@ ArturoTorresSánchezนั่นเป็นเหตุผลที่ฉันเพิ่มตัวระบุ "นาม": P
Jared Smith

1
@konrad สำหรับการอ้างอิงโดยค่าเริ่มต้นจาวาสคริปต์จะแสร้งทำเป็นว่าให้คุณเพิ่มคุณสมบัติให้กับแบบดั้งเดิมโดยไม่บ่นเมื่อคุณพยายามที่จะทำ การใช้โหมดเข้มงวดจะแก้ไขปัญหานั้นและโยน a TypeErrorหากคุณพยายามเพิ่มคุณสมบัติ (ดูjsbin.com/yovasafibo/edit?js,console )
Matthew Crumley

59

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

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


1
ฮ่า ๆ ใช่ฉันพูดถึงวัตถุเป็นทางเลือกที่ชัดเจนในคำถามของฉัน หลักการของความประหลาดใจน้อยที่สุดเป็นจุดที่ดีแม้ว่าด้วยออบเจ็กต์การพิมพ์ที่อ่อนแอของ JS จะทำให้ประหลาดใจน้อยลง แต่ก็ยังสับสนและคุณจำเป็นต้องตรวจสอบเอกสารอยู่ดี สำหรับการใช้งาน Modernizr เป็นตัวอย่างที่ดี: คุณมีชุดการทดสอบขนาดใหญ่ที่มีผลลัพธ์ที่เป็นเท็จ / เหมือนจริงและตอนนี้คุณต้องผ่านข้อมูลเพิ่มเติม - บางทีอาจเป็นความต้องการของผู้ที่มาในภายหลังดังนั้นเมื่อคุณสามารถ ทำการเปลี่ยนแปลงที่เกิดขึ้นกับห้องสมุดทั้งหมดโดยการสร้างตัวห่อซ้ำซ้อนส่วนใหญ่รอบบูลีนหรือคุณปรับปรุงบูล IMO ไม่ได้โง่ขนาดนั้น
Konrad

1
อีกเล็กน้อยเกี่ยวกับการใช้งาน หากคุณยึดติดกับการคืนค่าบูลีนคุณสามารถส่งผ่านฟังก์ชั่นทั้งหมดเพื่อแสดงรายการการดำเนินการเช่นใด ๆ (), ทั้งหมด (), ตัวกรอง () ได้อย่างง่ายดาย มันหลีกเลี่ยงการขาดการพิมพ์ที่แข็งแกร่งหรืออินเทอร์เฟซที่เป็นทางการใน JS ด้วยราคาที่ไม่ธรรมดาซึ่งดูเหมือนจะเป็นเหตุผลหลักที่ขัดแย้งกับมัน
Konrad

1
"แปลกใหม่" ดูเหมือนจะไม่เป็นข้อโต้แย้งที่แข็งแกร่งสำหรับฉัน
Robert Harvey

ฉันแก้ไขคำถาม นี่คือหลักการของความประหลาดใจอย่างน้อย :-)
konrad

16

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


คุณหมายถึงบูลีนหรือบูลีน (ด้วยตัวพิมพ์ใหญ่ B) ใน javascript มีความแตกต่าง
Pieter B

แต่ถ้าคุณมีวัตถุที่กำหนดสิ่งนี้และสิ่งอื่น ๆ มันไม่ได้ละเมิดเนื้อหาเดียวกันหรือไม่?
Casey

1
@Casey ไม่เนื่องจากวัตถุประสงค์ของวัตถุนั้นจะแตกต่างจากบูลีนดั้งเดิม และมันจะมีความรับผิดชอบเพียงอย่างเดียวในการสื่อสารสถานะและเหตุผลของการทำธุรกรรมเป็นตัวอย่าง
J. Pichardo

1
@ กรณีที่มีปัญหาไม่ใช่ว่ามีข้อมูลนี้ด้วยตัวเองเป็นการละเมิด SRP มันจะกลายเป็นปัญหาเมื่อรวมกับความรับผิดชอบที่บูลีนมีอยู่แล้ว - เพื่อแสดงถึงความจริงหรือเท็จ Booleanshenanigans ของ JavaScript แม้จะมี
Jacob Raihle

10

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

ในวิทยาการคอมพิวเตอร์ชนิดข้อมูลแบบบูลเป็นชนิดข้อมูลที่มีสองค่า (มักจะแสดงความจริงและเท็จ) ตั้งใจที่จะเป็นตัวแทนของค่าความจริงของตรรกะและพีชคณิตแบบบูล

(Bolding ของฉัน)


1
ถูกต้อง แต่อาจจำเป็นต้องกำหนดเป็นอย่างอื่น
svarog

8
@svarog สิ่งเดียวที่ฉันเห็นคือผู้ออกแบบโค้ดไร้ทักษะ หากคุณต้องการส่งคืนบูลและสิ่งอื่นให้สร้างคลาสหรือทูเปิลหรือรายการหรือสิ่งอื่นใดที่เหมาะกับรหัสเฉพาะ
MatthewRock

ถ้าคุณกลับมาใช่
svarog

ฉันคิดว่าคำถามเกี่ยวกับวัตถุบูลีนไม่ใช่แบบบูลดั้งเดิม วัตถุไม่ใช่ค่า
Pieter B

1
หากสามารถรับค่าอื่น ๆ นอกเหนือจากจริงหรือเท็จก็ยังไม่ได้บูลีน ซึ่งได้รับชื่อเป็นโง่
ไร้ประโยชน์

2

เพียงเพราะคุณไม่สามารถหมายความว่าคุณควรใน JS คุณสามารถแนบคุณสมบัติกับวัตถุใด ๆ (รวมถึงบูลีน)

เป็นสิ่งที่เลวร้ายอย่างไร

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

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

ตัวอย่างเช่นคุณสามารถแนบฟังก์ชั่นที่แปลงค่าบูลีนเป็นสตริงdirtyธงที่กลายเป็นจริงหากมีการเปลี่ยนแปลงค่าผู้ดูและการเรียกกลับเหตุการณ์ที่สามารถดำเนินการได้เมื่อมีการเปลี่ยนแปลงค่า ฯลฯ

แต่บูลีนที่ส่งคืน (Bool เป็นออบเจ็กต์ชั้นหนึ่งใน JS) มีคุณสมบัติที่ระบุรูปแบบที่รองรับ

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

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}

1
คุณหมายถึง boolean หรือ Boolean (with capital B) หรือเปล่า
Pieter B

1

คุณไม่สามารถสร้าง booleans ด้วยคุณสมบัติที่กำหนดเองใน JavaScript ล้มเหลวต่อไปนี้ (อย่างน้อยในหน่วย FF):

    var x = false;
    x.foo = "bar";
    console.log(x.foo);

คุณสามารถใช้หรือสืบทอดจากบูลีน แต่อย่างที่แมทธิวครัมลีย์บอกว่ามันให้ผลลัพธ์ที่แตกต่าง Booleanเป็นประเภท Objectเมื่อ JS ต้องการค่าบูลีนในการแสดงออกจะแปลงโดยใช้ฟังก์ชั่นสเปToBooleanซึ่งเอกสารที่ว่าสำหรับObjects trueผลเสมอ ดังนั้นค่าnew Boolean(false)ประเมินเป็นtrue! คุณสามารถตรวจสอบในตัวอย่างนี้: https://jsfiddle.net/md7abx5z/3/

เหตุผลเดียวที่ทำให้ Modernizr เป็นเรื่องบังเอิญ พวกเขาสร้างBooleanวัตถุก็ต่อเมื่อเงื่อนไขเป็นจริง falseเมื่อพวกเขาประเมินเท็จพวกเขาก็กลับสามัญ ดังนั้นจึงใช้งานได้เพราะพวกเขาจะส่งคืนBoolean วัตถุเมื่อผลลัพธ์นั้นเป็นจริงเท่านั้นและไม่เคยเมื่อมันเป็นเท็จ


1

ฉันเข้าใจว่าบริบทมีการเปลี่ยนแปลง แต่ฉันต้องการตอบคำถามต้นฉบับที่ฉันอ่านว่าใช้ JS เป็นตัวอย่าง แต่ไม่ จำกัด เพียงแค่ JS

การเพิ่มคุณสมบัติให้บูลีนจะไม่เป็นปัญหาหากคุณสมบัติมีบางอย่างเกี่ยวข้องกับ true / false ไม่ใช่กับตัวแปรที่ถือค่าไว้ ตัวอย่างเช่นการเพิ่มเมธอด toYesNoString จะไม่เป็นผลดีการเพิ่ม numberOfChildren ลงในค่า hasChildren ไม่ได้และไม่ต้องสงสัยคำถามนักเรียนที่ได้รับอนุญาต มีไม่มากที่คุณสามารถเพิ่มในบูลีนนอกเหนือไปจากการนำเสนอสตริงที่หลากหลายคุณสมบัติเดียวที่ฉันคิดได้ว่ามันสมเหตุสมผล แต่การเพิ่มเข้าไปไม่จำเป็นต้องเป็นความคิดที่ดีในทางทฤษฎี


0

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

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

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


0

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

  • อาร์เรย์ว่างหมายถึง "ไม่รองรับรูปแบบวิดีโอ" ซึ่งตามลำดับหมายถึง "ไม่รองรับวิดีโอ "
  • มิฉะนั้นหากรองรับรูปแบบวิดีโอใด ๆจะเห็นได้ว่ามีการรองรับวิดีโอโดยทั่วไป

อย่างน้อยฉันก็จะบอกว่าการใช้อาร์เรย์ค่อนข้างน่าแปลกใจน้อยกว่าการมี "บูลีนที่กำหนดเอง"

ในจาวาสคริปต์อาเรย์ที่ว่างยังถือว่าเป็นเท็จในขณะที่อาเรย์ที่ไม่ว่างนั้นเป็นความจริงดังนั้นด้วยโชคที่คุณสามารถสลับไปที่อาเรย์และทุกอย่างจะทำงานเหมือนก่อนที่จะ แก้ไข Nope ฉันคิดว่าฉันจำความจริงได้ ของวัตถุใน JavaScript: P


อาร์เรย์ที่ว่างเปล่าไม่ได้ประเมินว่าเป็นเท็จในคำสั่ง if if ([]) console.log ('ไม่เท็จ'); พิมพ์ 'ไม่ใช่เท็จ' ใน Chrome เช่น typeof [] === 'object' ดังนั้นจึงไม่มีอาเรย์ที่ว่างเปล่าไม่เป็นเท็จ ดูdeveloper.mozilla.org/en-US/docs/Glossary/Truthyสำหรับการอ้างอิง
joshp

@ จอชโอ๊ะโอ๊ะโอใช่แล้วฉันก็แย่ แก้ไขแล้ว
daniero

แม้ว่าฉันไม่แน่ใจว่าสิ่งที่ประเภทของพิสูจน์อะไร; ""มีประเภทของ"string"แต่จริง ๆ แล้วเป็นเท็จ
daniero

1
ในทางกลับกัน[].lengthคือความเท็จถ้าความยาว0ไม่พิมพ์มากขึ้นและในความคิดของฉันเป็นตัวบ่งชี้ความตั้งใจที่ดีกว่าจะดีกว่าif([])ถ้าเป็นไปได้
IllusiveBrian

@daniero ประเด็นเกี่ยวกับ typeof [] === 'object' คือวัตถุใด ๆ ที่เป็นความจริงแม้แต่ Boolean ใหม่ (false) ประเภทดั้งเดิมบางอย่าง (เช่นสตริง "" และหมายเลข 0) เป็นเท็จ แต่ไม่ได้เป็นวัตถุเท่าที่เกี่ยวข้องกับประเภทของ มันเป็นอีกวิธีหนึ่งในการจดจำ มันไม่เกี่ยวกับการพิสูจน์อะไรเลย หลักฐานอยู่ในสเปคหรือการทดสอบแล้วแต่จำนวนใดที่คุณต้องการ
joshp
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.