ฉันจะหลีกเลี่ยงพฤติกรรมแปดส่วนของ JavaScript ได้อย่างไร


283

ลองดำเนินการดังต่อไปนี้ใน JavaScript:

parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!

ฉันเพิ่งเรียนรู้วิธีที่ยากที่จาวาสคริปต์คิดว่าศูนย์นำจะระบุจำนวนเต็มฐานแปดและเนื่องจากไม่มี"8"หรือ"9"ในฐาน -8 ฟังก์ชันจะส่งกลับศูนย์ ชอบหรือไม่นี้เกิดจากการออกแบบ

วิธีแก้ปัญหาคืออะไร

หมายเหตุ: เพื่อความสมบูรณ์ฉันจะโพสต์โซลูชัน แต่เป็นวิธีแก้ปัญหาที่ฉันเกลียดดังนั้นโปรดโพสต์คำตอบอื่น ๆ / ดีกว่า


ปรับปรุง:

รุ่นที่ 5 ของมาตรฐาน JavaScript ( ECMA-262 ) แนะนำการเปลี่ยนแปลงแบบไม่ต่อเนื่องที่กำจัดพฤติกรรมนี้ Mozilla มีดีเขียนขึ้น


21
ขั้นตอนที่ 1) ทำตัวเองชอบและรวมถึง radix ตามที่ระบุไว้ในคำตอบก่อนหน้าเช่นเดียวกับในหนังสือของดั๊ก ขั้นตอนที่ 2) หากคุณจริงจังกับการเรียนรู้จาวาสคริปต์ให้นำหนังสือของดั๊กมาเอง มันมีค่ามาก หนังสือเล่มโปรดของฉันจนถึงตอนนี้ นี่คือความคิดเห็น fyi: realtech.burningbird.net/learning-javascript/basics/…
fuentesjr

8
ในเบราว์เซอร์ที่ใช้งานร่วมกันได้กับ ECMAScript 5th Edition เช่น Internet Explorer 9 พารามิเตอร์ฐานจะใช้ค่าเริ่มต้นเป็น10(ฐานสิบ) ยกเว้นว่าจะมีการใช้ตัวเลขในการวิเคราะห์คำนำหน้า0xเช่น0xFFในกรณีนี้พารามิเตอร์พื้นฐานจะเริ่มต้นที่ 16 หวังว่าในหนึ่งวัน จะเป็นความทรงจำที่ห่างไกล
Andy E

2
แล้วไง+'08' === 8ล่ะ ความจริง! บางทีคุณอาจต้องการparseIntรหัสจริงของคุณ แต่ไม่ใช่สำหรับรหัสด้านบน
kojiro

1
a) นี่ไม่ใช่ข้อผิดพลาดแก้ไขชื่อ b)Number('08')
OnTheFly

4
@portman: "รุ่นที่ 5 ... แนะนำการเปลี่ยนแปลงที่ทำลายพฤติกรรมนี้"น่าจะคุ้มค่าที่ชี้ให้เห็นว่าแม้ในรุ่นที่ 3 (13 ปีที่ผ่านมา) การใช้งานคือ "สนับสนุน" ไม่ควรทำ: "เมื่อ radix เป็น0หรือundefinedและหมายเลขของสตริงเริ่มต้นด้วย0ตัวเลขที่ไม่ได้ตามด้วยxหรือXจากนั้นการนำไปใช้อาจตีความตามจำนวนว่าเป็นฐานแปดหรือเป็นทศนิยมการใช้งานจะได้รับการสนับสนุนเพื่อตีความตัวเลขในกรณีนี้ว่าเป็นทศนิยม " ( สิ่งที่ฉันเน้น)
TJ Crowder

คำตอบ:


329

นี่เป็น gotcha Javascript ทั่วไปที่มีวิธีแก้ปัญหาง่าย ๆ :

เพียงระบุฐานหรือ 'radix' เช่น:

parseInt('08',10); // 8

คุณสามารถใช้หมายเลข :

Number('08'); // 8

57
จำนวน รุ่งโรจน์.
Portman

10
Number ต้องการเครื่องหมายคำพูดประมาณ 08 และเพิ่งได้รับการเตือนด้วย Number ('08 .123 ') จะสร้าง 8.123 เป็นเอาต์พุต หากคุณต้องการจำนวนเต็มจริงๆอย่าใช้ Number (หรือรูปแบบที่ตรงกับข้อมูลที่คุณป้อนเพื่อให้แน่ใจว่าเป็นจำนวนเต็มเท่านั้น)
304 Jason S

3
จำนวน (08); ให้ฉัน 8 ใน Firefox และ IE
เปาโล Bergantino

3
มันไม่ได้เป็นส่วนหนึ่งของมาตรฐาน ECMAscript ผมทดสอบบน JSDB ซึ่งใช้ Spidermonkey 1.7 (= เครื่องมือ Firefox JS) และบ่น "08 ไม่ได้เป็นตามกฎหมาย ECMA-262 คงฐานแปด"
เจสัน S

5
ยังใช้ '08' ในเครื่องหมายคำพูด 08 ไม่ตรงตามมาตรฐาน ECMA-262 และไม่รับประกันว่าจะประสบความสำเร็จโดยไม่มีคำเตือนและ / หรือข้อผิดพลาดและ / หรือพฤติกรรมที่เฉพาะเจาะจง
เจสัน S

43

หากคุณรู้ว่าค่าของคุณจะอยู่ในช่วงจำนวนเต็ม 32 บิตที่เซ็นชื่อแล้ว~~xจะทำสิ่งที่ถูกต้องในทุกสถานการณ์

~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99)  === -1

หากคุณค้นหาไบนารีไม่ใช่ ( ~) ข้อมูลจำเพาะต้องการการแปลง "ToInt32" สำหรับอาร์กิวเมนต์ที่ทำการแปลงที่ชัดเจนเป็น Int32 และระบุให้บังคับNaNค่าเป็นศูนย์

ใช่มันแฮ็คอย่างไม่น่าเชื่อ แต่สะดวก ...


2
ทำไมสองการดำเนินการเมื่อหนึ่งไบนารีหรือจะพอเพียง?
Oleg V. Volkov

@Oleg ทำไมหนึ่งพอเพียง?
เซบาสเตียน

3
@SebastianGodelet, | 0
Oleg V. Volkov

@Grodriguez และเมื่อ 0 ใน | 0 เป็นสตริง?
Oleg V. Volkov

คำถามทั้งหมดนี้เกี่ยวกับทางเลือกในการ parseInt สำหรับการแปลงสตริงเป็นจำนวนเต็ม ดังนั้น: เสมอ
Grodriguez

24

จากเอกสาร parseIntใช้อาร์กิวเมนต์ radixเลือกเพื่อระบุ base-10:

parseInt('08', 10); //equals 8
parseInt('09', 10); //equals 9

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


6
หากคุณไม่ชอบการใช้คำฟุ่มเฟือยเพียงแค่สร้างฟังก์ชั่นของคุณเองที่เรียกฟังก์ชั่นบิวอินในตัวและเติมอาร์กิวเมนต์ให้คุณคงที่เสมอ
304 Jason S

3
Riiiiiiight เพราะมันไม่เหมือนกับทุกคนใน StackOverflow ที่จะโจมตีคุณในการเขียนฟังก์ชัน parseIntB10 การเขียนฟังก์ชัน wrapper ของคุณเองเป็นความคิดที่แย่มากสำหรับจุดประสงค์นี้
Stefan Kendall

2
@iftrue: ฉันคิดว่าคุณพลาดจุดของฉัน โดยส่วนตัวฉันไม่รังเกียจที่จะทำ parseInt (someString, 10) ทุกที่เพื่อให้แน่ใจว่าฉันบังคับฐาน 10 OP ดูเหมือนจะไม่ชอบวิธีการนี้ดังนั้นฉันจึงแนะนำทางเลือกอื่นซึ่งฉันจะไม่ใช้เป็นการส่วนตัว จำเป็น (อันนี้เห็นได้ชัดคือความคิดที่อยู่เบื้องหลัง JQuery: ทำให้สะดวกโดยการเพิ่มความซับซ้อนเป็นพิเศษฉันไม่ได้ใช้ JQuery แต่หลายคนพบว่ามีประโยชน์..)
เจสัน S

4
ที่จริงแล้วการห่อหุ้มparseIntเพื่อความสะดวกในการใช้งานฟังก์ชั่นเช่นmapใน["7","4","09","5"].map(parseInt); Mapนั้นจะส่งดัชนีขององค์ประกอบในอาร์เรย์เป็นอาร์กิวเมนต์ที่สองซึ่งจะถูกตีความโดยparseIntเป็นฐานเว้นแต่คุณจะห่อ
Plynx

11
function parseDecimal(s) { return parseInt(s, 10); }

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


10

ระบุฐาน:

var number = parseInt(s, 10);

ว้าวพวกคุณเร็วมาก ฉันยังมีคำตอบของฉันบนคลิปบอร์ด คุณเสียบเข้ากับอินเทอร์เน็ตสไตล์นีโอโดยตรงหรือไม่?
Portman

1
ทำไมปีศาจจึงไม่ผิดนัดฐาน 10
Tom Gullen

2
อาจเป็นเพราะไม่ได้หมายถึงฟังก์ชั่นการแปลงแบบ String-> Number เป็นหลัก แต่ฟังก์ชั่นที่อ่านตัวเลขจากหมายเลขฐานขสตริง
artistoex

2
มันเป็นค่าเริ่มต้นที่ฐาน 10 แต่ศูนย์นำหน้าเป็นวิธีที่แพร่หลายเพื่อระบุฐานแปด
นาธาน

7

มันจะซนมากที่จะแทนที่ parseInt กับรุ่นที่สมมติว่าเป็นทศนิยมถ้าไม่มีพารามิเตอร์ที่สองหรือไม่? (หมายเหตุ - ไม่ได้ทดสอบ)

parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}

2
ใช่ว่ามันจะซน - มันจะทำลายรหัสอื่น ๆ ที่อาศัยพฤติกรรมมาตรฐาน
jes5199

4
นั่นเป็นความจริง แต่ก็มีไม่มาก นอกจากนี้ยังไม่ใช่พฤติกรรมมาตรฐาน - การสนับสนุนฐานแปดเป็นตัวเลือก
Andrew Duffy

2
แต่คุณกำลังทิ้งการสนับสนุนฐานสิบหกซึ่งไม่ใช่ตัวเลือกใช่ไหม สิ่งนี้ควรเป็นจริงเสมอ: parseInt("0xFFFFFF") === 16777215แต่ด้วยการแฮ็คที่ซุกซนของคุณในสถานที่มันไม่ทำงานอีกต่อไปparseInt("0xFFFFFF") === 0
ติโม


6

คุณอาจใช้ parseFloat หรือ parseInt แทนการใช้ตัวดำเนินการ unary ( + )

+"01"
// => 1

+"02"
// => 2

+"03"
// => 3

+"04"
// => 4

+"05"
// => 5

+"06"
// => 6

+"07"
// => 7

+"08"
// => 8

+"09"
// => 9

และสำหรับการวัดที่ดี

+"09.09"
// => 9.09

ลิงค์ MDN

ตัวดำเนินการ unary plus นำหน้าตัวถูกดำเนินการและประเมินเป็นตัวถูกดำเนินการ แต่พยายามแปลงเป็นตัวเลขหากยังไม่ได้ดำเนินการ แม้ว่า unary negation (-) สามารถแปลงตัวเลขที่ไม่ใช่ตัวเลขได้ แต่unary plus เป็นวิธีที่เร็วที่สุดและต้องการแปลงบางสิ่งให้เป็นตัวเลขเพราะมันไม่ได้ทำการดำเนินการอื่นใดกับตัวเลข



4

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

window._oldParseInt = window.parseInt;
window.parseInt = function(str, rad) {
    if (! rad) {
        return _oldParseInt(str, 10);
    }
    return _oldParseInt(str, rad);
};

ซึ่งอาจทำให้ผู้อ่านในภายหลังสับสนดังนั้นการสร้างฟังก์ชัน parseInt10 () อาจอธิบายตนเองได้มากกว่า โดยส่วนตัวแล้วฉันชอบที่จะใช้ฟังก์ชั่นที่เรียบง่ายมากกว่าการเพิ่ม ", 10" ตลอดเวลา - เพียงแค่สร้างโอกาสมากขึ้นสำหรับข้อผิดพลาด


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