จริงๆ แล้ว Typeof ใน JavaScript นั้นซับซ้อนมาก มันสามารถนำมาใช้ทำอะไรได้หลายอย่าง แต่ก็มีพฤติกรรมแปลกๆ มากมายเช่นกัน บทความนี้แสดงรายการการใช้งานที่หลากหลาย และยังชี้ให้เห็นถึงปัญหาและแนวทางแก้ไขที่มีอยู่ด้วย
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Ftypeof
> ประเภทของไม่ได้กำหนด
'ไม่ได้กำหนด'
> typeof null // ข้อผิดพลาดที่รู้จักกันดี
'วัตถุ'
> ประเภทของจริง
'บูลีน'
>ประเภท 123
'ตัวเลข'
> พิมพ์ "abc"
'สตริง'
> ประเภทของฟังก์ชัน() {}
'การทำงาน'
> ประเภทของ {}
'วัตถุ'
> ประเภทของ []
'วัตถุ'
> ประเภทของตัวแปรที่ไม่รู้จัก
'ไม่ได้กำหนด'
1. ตรวจสอบว่ามีตัวแปรอยู่และมีค่าหรือไม่
typeof จะส่งกลับ "unknown" ในสองสถานการณ์: เมื่อตัวแปรไม่ได้รับการประกาศ และเมื่อค่าของตัวแปรไม่ได้ถูกกำหนด ตัวอย่างเช่น:
> typeof undeclaredVariable === "ไม่ได้กำหนด" จริง > var ประกาศตัวแปร; > typeof ประกาศตัวแปร 'ไม่ได้กำหนด' > ประเภทของไม่ได้กำหนด 'ไม่ได้กำหนด'
มีวิธีอื่นๆ ในการตรวจสอบว่าค่าไม่ได้ถูกกำหนดไว้หรือไม่:
> ค่า var = ไม่ได้กำหนด; > ค่า === ไม่ได้กำหนด จริง
แต่หากใช้วิธีนี้กับตัวแปรที่ไม่ได้ประกาศ ข้อยกเว้นจะถูกส่งออกไป เนื่องจากมีเพียง typeof เท่านั้นที่สามารถตรวจจับตัวแปรที่ไม่ได้ประกาศได้ตามปกติโดยไม่ต้องรายงานข้อผิดพลาด:
> undeclaredVariable === ไม่ได้กำหนด ReferenceError: undeclaredVariable ไม่ได้ถูกกำหนดไว้
หมายเหตุ: ตัวแปรที่ไม่ได้เตรียมใช้งาน พารามิเตอร์ทางการที่ไม่มีพารามิเตอร์ผ่าน และคุณสมบัติที่ไม่มีอยู่จริงจะไม่มีปัญหาข้างต้น เนื่องจากสามารถเข้าถึงได้ตลอดเวลาและค่าไม่ได้ถูกกำหนดไว้เสมอ:
> var ประกาศตัวแปร; > ประกาศตัวแปร === ไม่ได้กำหนด จริง > (ฟังก์ชัน (x) { กลับ x === ไม่ได้กำหนด }()) จริง > ({}).foo === ไม่ได้กำหนด จริง
หมายเหตุผู้แปล: ดังนั้น หากคุณต้องการตรวจจับการมีอยู่ของตัวแปรส่วนกลางที่อาจไม่ได้รับการประกาศ คุณสามารถใช้ if(window.maybeUndeclaredVariable){}
ปัญหา: typeof ยุ่งยากในการทำงานดังกล่าวให้สำเร็จ
วิธีแก้ไข: การดำเนินการประเภทนี้ไม่ได้เกิดขึ้นบ่อยนัก ดังนั้นบางคนจึงรู้สึกว่าไม่จำเป็นต้องหาวิธีแก้ปัญหาที่ดีกว่านี้ แต่อาจมีบางคนเสนอผู้ดำเนินการพิเศษ:
> กำหนด undeclaredVariable เท็จ > var ประกาศตัวแปร; > กำหนดประกาศตัวแปรเท็จ
หรือบางทีอาจต้องการตัวดำเนินการที่ตรวจจับว่ามีการประกาศตัวแปรหรือไม่:
> ประกาศ unclaredVariable เท็จ > var ประกาศตัวแปร; > ประกาศประกาศตัวแปรจริง
หมายเหตุผู้แปล: ในภาษา Perl ตัวดำเนินการที่กำหนดข้างต้นเทียบเท่ากับกำหนด () และตัวดำเนินการที่ประกาศไว้ด้านบนเทียบเท่ากับมีอยู่ ()
2. ตรวจสอบว่าค่าไม่เท่ากับไม่ได้กำหนดหรือเป็นโมฆะ
ปัญหา: หากคุณต้องการตรวจสอบว่าค่าถูกกำหนดไว้แล้วหรือไม่ (ค่าไม่ใช่ทั้งไม่ได้กำหนดและเป็นค่าว่าง) คุณจะพบกับลักษณะเฉพาะที่มีชื่อเสียงที่สุดของ typeof (ถือว่าเป็นจุดบกพร่อง): typeof null ส่งคืน "object":
> ประเภทของ null 'วัตถุ'
หมายเหตุผู้แปล: นี่อาจกล่าวได้ว่าเป็นข้อบกพร่องในการใช้งาน JavaScript ดั้งเดิม และนี่คือวิธีที่มาตรฐานได้รับมาตรฐานในขณะนี้ เมื่อแก้ไขและใช้งานประเภท null === "null" แล้ว แต่ท้ายที่สุดก็พิสูจน์แล้วว่าไม่สามารถทำได้ //wiki .ecmascript.org/doku.php?id=harmony:typeof_null
วิธีแก้ไข: อย่าใช้ typeof สำหรับงานนี้ ให้ใช้ฟังก์ชันเช่นนี้แทน:
ฟังก์ชั่น isDefined(x) { return x !== null && x !== ไม่ได้กำหนด;
ความเป็นไปได้อีกอย่างหนึ่งคือการแนะนำ "ตัวดำเนินการค่าเริ่มต้น" โดยที่นิพจน์ต่อไปนี้ส่งคืน defaultValue หากไม่ได้กำหนด myValue:
myValue ?? ค่าเริ่มต้น
นิพจน์ข้างต้นเทียบเท่ากับ:
(myValue !== ไม่ได้กำหนด && myValue !== null) ? myValue : defaultValue
หรือ:
myValue ??= defaultValue
อันที่จริงมันเป็นการทำให้ข้อความต่อไปนี้ง่ายขึ้น:
myValue = myValue ?? ค่าเริ่มต้น
เมื่อคุณเข้าถึงคุณสมบัติที่ซ้อนกัน เช่น แถบ คุณอาจต้องการความช่วยเหลือจากโอเปอเรเตอร์นี้:
obj.foo.bar
หากไม่ได้กำหนด obj หรือ obj.foo นิพจน์ด้านบนจะส่งข้อยกเว้น ตัวดำเนินการด้านบนจะส่งคืนค่าแรกที่พบเมื่อสำรวจผ่านเลเยอร์คุณสมบัติทีละเลเยอร์คุณสมบัติที่ไม่ได้กำหนดหรือเป็นโมฆะ:
obj.??fo.??bar
นิพจน์ข้างต้นเทียบเท่ากับ:
(obj === ไม่ได้กำหนด || obj === null) ? obj : (obj.foo === ไม่ได้กำหนด || obj.foo === null) ? obj.foo : obj.foo.bar
3. แยกแยะระหว่างค่าวัตถุและค่าดั้งเดิม
ฟังก์ชันต่อไปนี้จะทดสอบว่า x เป็นค่าอ็อบเจ็กต์หรือไม่:
ฟังก์ชั่น isObject(x) { return (typeof x === "function" || (typeof x === "object" && x !== null));
ปัญหา: การตรวจจับข้างต้นมีความซับซ้อนเนื่องจาก typeof ถือว่าฟังก์ชันและวัตถุเป็นประเภทที่แตกต่างกัน และ typeof null จะส่งกลับ "วัตถุ"
วิธีแก้ไข: วิธีการต่อไปนี้มักใช้เพื่อตรวจจับค่าอ็อบเจ็กต์:
ฟังก์ชั่น isObject2(x) { ส่งคืน x === วัตถุ (x);
คำเตือน: คุณอาจคิดว่าคุณสามารถใช้ instanceof Object เพื่อตรวจจับได้ที่นี่ แต่ instanceof จะกำหนดความสัมพันธ์ของอินสแตนซ์โดยใช้ต้นแบบของวัตถุ แล้ววัตถุที่ไม่มีต้นแบบล่ะ:
> var obj = Object.create(null); > Object.getPrototypeOf(obj) null
obj นั้นเป็นวัตถุจริงๆ แต่ไม่ใช่อินสแตนซ์ของค่าใดๆ:
> typeof obj 'วัตถุ' > obj อินสแตนซ์ของวัตถุเท็จ
ในทางปฏิบัติ คุณอาจไม่ค่อยพบวัตถุดังกล่าว แต่มันมีอยู่จริงและมีประโยชน์
หมายเหตุผู้แปล: Object.prototype เป็นวัตถุที่มีอยู่ตามค่าเริ่มต้นและไม่มีต้นแบบ
>Object.getPrototypeOf(Object.prototype)null>typeof Object.prototype'object'>Object.prototype อินสแตนซ์ของ Object false
4.ค่าพื้นฐานเป็นประเภทใด
typeof เป็นวิธีที่ดีที่สุดในการตรวจสอบประเภทของค่าดั้งเดิม
> typeof "abc" 'string' > typeof ไม่ได้กำหนด 'ไม่ได้กำหนด'
ปัญหา: คุณต้องตระหนักถึงพฤติกรรมแปลก ๆ ของ typeof null
> typeof null // ระวัง 'วัตถุ'
วิธีแก้ไข: ฟังก์ชันต่อไปนี้สามารถแก้ไขปัญหานี้ได้ (เฉพาะกรณีการใช้งานนี้เท่านั้น)
ฟังก์ชั่น getPrimitiveTypeName(x) { var typeName = typeof x; switch(typeName) { case "unknown": case "boolean": case "number": case "string": return typeName; case "object": if (x == = null) { return "null"; } ค่าเริ่มต้น: // ไม่มีการตัดสินก่อนหน้านี้โยน TypeError ใหม่ ("พารามิเตอร์ไม่ใช่ค่าดั้งเดิม: "+x } }
วิธีแก้ปัญหาที่ดีกว่า: ใช้ฟังก์ชัน getTypeName() ซึ่งนอกเหนือจากการส่งคืนประเภทของค่าดั้งเดิมแล้ว ยังสามารถส่งคืนแอตทริบิวต์ภายใน [[Class]] ของค่าอ็อบเจ็กต์ได้ ต่อไปนี้คือวิธีการใช้ฟังก์ชันนี้ (หมายเหตุของผู้แปล: jQuery $.type เป็นการใช้งานดังกล่าว)
5. ไม่ว่าค่าบางอย่างจะเป็นฟังก์ชันหรือไม่
typeof สามารถใช้เพื่อตรวจสอบว่าค่าเป็นฟังก์ชัน > typeof function () {} 'function' > typeof Object.prototype.toString 'function'
โดยหลักการแล้ว อินสแตนซ์ของ ฟังก์ชันยังสามารถตรวจจับข้อกำหนดนี้ได้ เมื่อมองแวบแรก ดูเหมือนว่าวิธีการเขียนจะดูหรูหรากว่า อย่างไรก็ตาม เบราว์เซอร์มีนิสัยแปลก: แต่ละเฟรมและหน้าต่างมีตัวแปรส่วนกลางของตัวเอง วัตถุถูกส่งผ่านไปยังกรอบงานอื่น instanceof จะทำงานไม่ถูกต้องเนื่องจากทั้งสองกรอบงานมีตัวสร้างที่แตกต่างกัน นี่คือเหตุผลว่าทำไมจึงมีเมธอด Array.isArray() ใน ECMAScript 5 คงจะดีถ้ามีเมธอดแบบข้ามเฟรมเวิร์กสำหรับการตรวจสอบว่าอ็อบเจ็กต์เป็นอินสแตนซ์ของคอนสตรัคเตอร์ที่กำหนด getTypeName( ) ข้างต้นเป็นวิธีการแก้ปัญหาชั่วคราวหรือไม่ แต่อาจมีวิธีแก้ปัญหาขั้นพื้นฐานกว่านี้
6.ภาพรวม
สิ่งที่กล่าวถึงต่อไปนี้ควรเป็นคุณสมบัติที่จำเป็นเร่งด่วนที่สุดใน JavaScript ในปัจจุบัน และสามารถแทนที่คุณสมบัติการทำงานบางอย่างของความรับผิดชอบในปัจจุบันของ typeof:
isDefined() (เช่น Object.isDefined()): สามารถใช้เป็นฟังก์ชันหรือตัวดำเนินการได้
เป็นวัตถุ()
getTypeName()
กลไกข้ามเฟรมเวิร์กสำหรับการตรวจสอบว่าวัตถุเป็นตัวอย่างของตัวสร้างที่ระบุหรือไม่
ความจำเป็นในการตรวจสอบว่ามีการประกาศตัวแปรหรือไม่อาจไม่จำเป็นต้องมีตัวดำเนินการของตัวเอง