ทำไม `null> = 0 && null <= 0` แต่ไม่ใช่` null == 0`


142

ฉันต้องเขียนรูทีนที่เพิ่มค่าของตัวแปรด้วย 1 ถ้าชนิดของมันคือnumberและกำหนด 0 ให้กับตัวแปรถ้าไม่ใช่โดยที่ตัวแปรนั้นเริ่มต้นnullหรือundefinedหรือ

การใช้งานครั้งแรกเป็นv >= 0 ? v += 1 : v = 0เพราะฉันคิดว่าอะไรที่ไม่ใช่จำนวนจะทำให้นิพจน์ทางคณิตศาสตร์เป็นเท็จ แต่มันผิดเนื่องจากnull >= 0ถูกประเมินเป็นจริง จากนั้นฉันได้เรียนรู้nullพฤติกรรมเช่น 0 และนิพจน์ต่อไปนี้ล้วนได้รับการประเมินว่าเป็นจริง

  • null >= 0 && null <= 0
  • !(null < 0 || null > 0)
  • null + 1 === 1
  • 1 / null === Infinity
  • Math.pow(42, null) === 1

แน่นอนnullไม่ใช่ 0 null == 0ถูกประเมินเป็นเท็จ สิ่งนี้ทำให้การแสดงออกที่ดูเหมือนซ้ำซาก(v >= 0 && v <= 0) === (v == 0)ผิดพลาด

เหตุใดจึงเป็นnullเช่น 0 ถึงแม้ว่ามันจะไม่ใช่ 0 จริง ๆ


3
เขากำลังพูดถึง Javascript ตัวอย่างของคุณอยู่ใน PHP ในผู้ประกอบการ PHP == เปรียบเทียบค่าด้วยวิธีพิเศษ คุณสามารถทำการเปรียบเทียบที่บ้าสุด ๆ เช่น "10" == "1e1" (ซึ่งเป็นเรื่องจริง) หากคุณใช้โอเปอเรเตอร์ === คุณจะได้รับผลลัพธ์ที่แตกต่างกันโดยสิ้นเชิงเพราะมันจะตรวจสอบว่าประเภทนั้นตรงกับค่าหรือไม่ ตรวจสอบลิงค์นี้: php.net/manual/en/language.operators.comparison.php
Pijusn

ตัวดำเนินการ PHP '==' ทำงานในลักษณะ "พิเศษ" จริงๆ
นักเล่นแร่แปรธาตุ Two-Bit

หากความต้องการของคุณคือการเริ่มนับที่ 1 แทน 0 มีวิธีสั้น ๆ จริง ๆ เพื่อเพิ่มเคาน์เตอร์ที่เริ่มต้นอย่างใดอย่างหนึ่งnullหรือundefined:c = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral

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

1
@AtesGoral - terse แต่ไม่ชัดเจน ควรเตือนผู้คนว่าเมื่อใดก็ตามที่ทำสิ่งที่ไม่ชัดเจนโปรดเพิ่มความคิดเห็นเพื่ออธิบายว่าโค้ดทำอะไร ในสถานการณ์ส่วนใหญ่ฉันจะพิจารณาว่าเป็น "การปรับให้เหมาะสมก่อนกำหนด" เนื่องจากมีการซื้อขายที่ชัดเจนสำหรับกำไรที่เพิ่มขึ้นเล็กน้อย
ToolmakerSteve

คำตอบ:


207

คำถามที่แท้จริงของคุณดูเหมือนจะเป็น:

ทำไม:

null >= 0; // true

แต่:

null == 0; // false

สิ่งที่เกิดขึ้นจริง ๆ คือผู้ประกอบการ ( >=) ดีกว่าหรือเท่ากับดำเนินการข่มขู่ ( ToPrimitive) ด้วยประเภทคำใบ้Numberจริง ๆ แล้วผู้ประกอบการสัมพันธ์ทั้งหมดมีพฤติกรรมนี้

nullได้รับการดูแลในวิธีพิเศษโดยEquals Operator ( ==) โดยสังเขปมันแค่coercesเพื่อundefined:

null == null; // true
null == undefined; // true

ค่าเช่นfalse, '', '0'และ[]อาจมีการบังคับขู่เข็ญประเภทตัวเลขทั้งหมดของพวกเขาบีบบังคับให้เป็นศูนย์

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

สรุป:

  • การเปรียบเทียบเชิงสัมพันธ์: หากทั้งสองค่าไม่ได้เป็นประเภทสตริงToNumberจะถูกเรียกทั้งสองอย่าง นี้เป็นเช่นเดียวกับการเพิ่ม+ในด้านหน้าซึ่งสำหรับ coerces null 0ไป

  • การเปรียบเทียบความเท่าเทียมกัน: โทรเฉพาะสายToNumberอักขระตัวเลขและบูลีนเท่านั้น


1
สวัสดี CMS ตามคำอธิบายของคุณ null ดั้งเดิมคือ 0 ดังนั้น 0> = 0 คืนค่า true และ == กำลังส่งคืน false.but ตามอัลกอริทึม ecma หาก Type (x) เป็น Object และ Type (y) เป็น String หรือ Number ส่งคืนผลลัพธ์ของการเปรียบเทียบ ToPrimitive (x) == y.th จากนั้นก็ควรคืนค่าจริงโปรดอธิบายฉัน
bharath muppa

สำหรับฉันคำตอบไม่ได้ให้คำตอบ - null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:- และอะไร คุณอธิบายได้null >= 0ไหม :)
Andrey Deineko

@bharathmuppa @ andrey-deineko: คำตอบที่เหลือของ CMS อยู่ที่นี่: อัลกอริธึมการเปรียบเทียบเชิงเปรียบเทียบเชิงนามธรรม ซึ่งอธิบายไว้ในจุดที่ 3 ว่าถ้าค่าทั้งสองไม่ใช่ประเภท String, ToNumber จะถูกเรียกทั้งคู่ นี้เป็นเช่นเดียวกับการเพิ่ม+ในด้านหน้าซึ่งสำหรับ coerces null 0ไป ความเสมอภาคเรียก ToNumber บน Strings, Numbers และ Booleans เท่านั้น
Michael Liquori

7
คำอธิบายที่ดี แต่ฉันไม่ชอบ ในภาษาใด ๆ (x == 0 || x> 0) ควรเท่ากับ (x> = 0) javascript เป็นภาษาที่โง่
John Henckel

1
มันเป็นข้อผิดพลาดในสเป็คจริงๆ (เพราะในทางคณิตศาสตร์มันผิด) และไม่มีอะไรที่ต้องทำเพราะเว็บไซต์นับล้านต้องอาศัยการเปรียบเทียบค่าว่าง ^^ '
mahieddine

14

ฉันต้องการขยายคำถามเพื่อปรับปรุงการมองเห็นปัญหาให้ดียิ่งขึ้น:

null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0;  //false
null < 0;  //false

มันก็ไม่สมเหตุสมผล เช่นเดียวกับภาษาของมนุษย์สิ่งเหล่านี้จำเป็นต้องเรียนรู้ด้วยหัวใจ


1
ตามที่อธิบายไว้ข้างต้นสามารถอธิบายได้โดยมีข้อยกเว้นเช่นเดียวกับวิธี == ปฏิบัติต่อ null มิฉะนั้นในทุกกรณี null จะถูกแปลงเป็น 0 โดยใช้ Number (nulll)
Sourabh Ranka

5

JavaScript มีการเปรียบเทียบทั้งแบบเข้มงวดและแบบแปลง

null >= 0;เป็นจริง แต่ (null==0)||(null>0)เป็นเท็จ

null <= 0;เป็นจริง แต่(null==0)||(null<0)เป็นเท็จ

"" >= 0 เป็นจริงเช่นกัน

สำหรับการเปรียบเทียบเชิงสัมพันธ์เชิงนามธรรม (<=,> =) ตัวถูกดำเนินการจะถูกแปลงเป็นแบบดั้งเดิมก่อนแล้วจึงเป็นชนิดเดียวกันก่อนการเปรียบเทียบ

typeof null returns "object"

เมื่อ type คือ object javascript พยายามทำให้วัตถุเป็นวัตถุ (เช่น null) ขั้นตอนต่อไปนี้จะถูกนำมาใช้ ( ECMAScript 2015 ):

  1. ถ้าPreferredTypeยังไม่ผ่านให้hintเป็น "ค่าเริ่มต้น"
  2. ถ้าPreferredTypeเป็นhintString ให้hintเป็น "string"
  3. อื่นPreferredTypeคือhintNumber ให้hintเป็น "number"
  4. อนุญาตเป็นexoticToPrimGetMethod(input, @@toPrimitive)
  5. ReturnIfAbrupt(exoticToPrim).
  6. ถ้าexoticToPrimไม่ได้ไม่ได้กำหนดแล้ว
    ) Call(exoticToPrim, input, «hint»)ที่ให้ผลเป็น ข)
    c) ถ้าไม่ใช่ Object ให้ส่งคืนผลลัพธ์ReturnIfAbrupt(result)
    Type(result)
    d) โยนข้อยกเว้น TypeError
  7. หากhintเป็น "ค่าเริ่มต้น" ให้hintเป็น "หมายเลข"
  8. OrdinaryToPrimitive(input,hint)กลับ

ค่าที่อนุญาตสำหรับคำใบ้คือ "default", "number" และ "string" วัตถุวันที่จะไม่ซ้ำกันในหมู่วัตถุ ECMAScript ในตัวที่พวกเขาถือว่า "เริ่มต้น" เป็นเทียบเท่ากับ "สตริง" อื่น ๆ ทั้งหมดในตัว ECMAScript วัตถุรักษา "เริ่มต้น" ในฐานะที่เป็นเทียบเท่ากับ "จำนวน" ( ECMAScript 20.3.4.45 )

ดังนั้นฉันคิดว่าnullแปลงเป็น 0


1

ผมมีปัญหาเหมือนกัน !!. ปัจจุบันทางออกเดียวของฉันคือการแยก

var a = null;
var b = undefined;

if (a===0||a>0){ } //return false  !work!
if (b===0||b>0){ } //return false  !work!

//but 
if (a>=0){ } //return true !

if (a!=null && a>=0)มันอาจจะเป็นที่ชัดเจนแทนที่จะทำ: สิ่งนี้จะชี้แจงเหตุผลที่ไม่เพียง แต่ทำ>=ด้วยตัวเอง: "a อาจเป็นโมฆะ (หรือไม่ได้กำหนดซึ่งก็คือ '== null')"
ToolmakerSteve

0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

ในทางคณิตศาสตร์มันแปลก ผลลัพธ์สุดท้ายระบุว่า "โมฆะนั้นมากกว่าหรือเท่ากับศูนย์" ดังนั้นหนึ่งในการเปรียบเทียบข้างต้นต้องเป็นจริง แต่ทั้งคู่เป็นเท็จ

เหตุผลก็คือการตรวจสอบความเท่าเทียมกัน==และการเปรียบเทียบ> < >= <=ทำงานแตกต่างกัน เปรียบเทียบแปลง null 0ไปยังหมายเลขที่รักษามันเป็น นั่นเป็นเหตุผลที่ (3) null >= 0เป็นtrueและ (1) คือnull > 0false

บนมืออื่น ๆ , การตรวจสอบความเท่าเทียมกัน==สำหรับการundefinedและnullมีการกำหนดดังกล่าวว่าโดยไม่ต้องแปลงใด ๆ พวกเขาเท่ากับแต่ละอื่น ๆ และทำอะไรไม่เท่ากับที่อื่น นั่นเป็นเหตุผลที่ (2) คือnull == 0false

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