ตรวจสอบ JavaScript เป็นศูนย์


170

ฉันเจอรหัสต่อไปนี้:

function test(data) {
    if (data != null && data !== undefined) {
        // some code here
    }
}

ฉันค่อนข้างใหม่กับ JavaScript แต่จากคำถามอื่น ๆ ที่ฉันได้อ่านที่นี่ฉันรู้สึกว่ารหัสนี้ไม่สมเหตุสมผล


โดยเฉพาะคำตอบนี้ระบุว่า

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

อัปเดต:คำตอบ (อ้างถึง) ด้านบนอาจทำให้เข้าใจผิด มันควรจะพูดว่า«ตัวแปรที่ไม่ได้ประกาศ»แทนที่จะ«ตัวแปรไม่ได้กำหนด»

ดังที่ฉันค้นพบในคำตอบของRyan ♦ , maericsและnwellnhofถึงแม้ว่าจะไม่มีการขัดแย้งกับฟังก์ชันฟังก์ชันตัวแปรสำหรับอาร์กิวเมนต์จะถูกประกาศเสมอ ความจริงข้อนี้ยังพิสูจน์ข้อแรกในรายการด้านล่าง


จากความเข้าใจของฉันสถานการณ์ต่อไปนี้อาจประสบ:

  • ฟังก์ชั่นได้รับการเรียกว่ามีการขัดแย้งใดจึงทำให้ตัวแปรไม่ได้กำหนดและการสร้างข้อผิดพลาดในdatadata != null

  • ฟังก์ชั่นถูกเรียกโดยเฉพาะอย่างยิ่งกับnull(หรือundefined) เป็นอาร์กิวเมนต์ในกรณีที่data != nullได้รับการปกป้องรหัสภายในทำให้การแสดงผลที่&& data !== undefinedไร้ประโยชน์

  • ฟังก์ชั่นถูกเรียกด้วยอาร์กิวเมนต์ null ไม่ใช่ในกรณีที่มันนิด ๆ จะผ่านทั้งสองและdata != null data !== undefined

ถาม: ความเข้าใจของฉันถูกต้องหรือไม่


ฉันได้ลองทำสิ่งต่อไปนี้ในคอนโซลของ Firefox:

--
[15:31:31.057] false != null
[15:31:31.061] true
--
[15:31:37.985] false !== undefined
[15:31:37.989] true
--
[15:32:59.934] null != null
[15:32:59.937] false
--
[15:33:05.221] undefined != null
[15:33:05.225] false
--
[15:35:12.231] "" != null
[15:35:12.235] true
--
[15:35:19.214] "" !== undefined
[15:35:19.218] true

ฉันไม่สามารถคิดออกกรณีที่data !== undefined หลังจากที่ data != nullอาจจะมีการใช้งานใด ๆ


9
if (data)ใช้เพียงแค่ เป็นวิธีที่ช่วยในการจำ Javascript เพื่อตรวจสอบว่าdataตัวแปรประเมินว่าเป็นจริงหรือไม่ undefined,, nullfalse, 0, สตริงว่าง, อาร์เรย์ว่างเปล่าและ (?) วัตถุที่ไม่มีคุณสมบัติประเมินค่าเป็นเท็จส่วนที่เหลือเป็นจริง
J0HN

20
@ J0HN - การใช้if(data)หมายความว่าเขาไม่สามารถผ่านfalseหรือ0เป็นค่าdataได้
techfoobar

@ J0HN นอกจากนี้คำตอบเดียวกันฉันพูดถึงยังระบุว่า: และif(typeof someUndefVar == whatever) -- works if(someUnderVar) -- error
afsantos

2
มันอาจจะควรจะเป็นdata !== null && data !== undefinedซึ่งเทียบเท่ากับซึ่งเทียบเท่ากับdata != null data != undefinedรูปแบบเดิมมีแนวโน้มที่จะได้รับการสนับสนุนเนื่องจากมีความชัดเจนมากขึ้นเกี่ยวกับเงื่อนไขในขณะที่มันจะมองข้ามได้ง่ายว่าทั้งสองnullและundefinedกำลังถูกตรวจสอบด้วยสองเงื่อนไขในภายหลัง
zzzzBov

2
โดยวิธีการทดสอบที่ชัดเจนสำหรับundefinedIMO เป็นกลิ่นรหัส ไม่ใช่คำหลักที่ได้รับการป้องกันเหมือนกับnullเป็นตัวแปรที่ไม่ได้กำหนด นี่คือที่ถูกต้องครบถ้วนและเป็นไปเพื่อทำลายรหัสของคุณ:undefined = 1
Izkata

คำตอบ:


106

เป็น“ตัวแปรไม่ได้กำหนด” undefinedจะแตกต่างจากค่า

ตัวแปรที่ไม่ได้กำหนด:

var a;
alert(b); // ReferenceError: b is not defined

ตัวแปรที่มีค่าundefined:

var a;
alert(a); // Alerts “undefined”

เมื่อฟังก์ชั่นรับการโต้เถียงอาร์กิวเมนต์นั้นจะถูกประกาศเสมอแม้ว่าค่าของมันจะเป็นundefinedเช่นนั้นและจะไม่มีข้อผิดพลาดใด ๆ แม้ว่าคุณจะถูก!= nullตามมาด้วย!== undefinedการไร้ประโยชน์ก็ตาม


32
data !== null && data !== undefinedจะทำให้รู้สึกถึงแม้ว่า
bfavaretto

@bfavaretto: ใช่ดังนั้นจริง ๆ แล้วมันอาจจะเป็นพิมพ์ผิด แต่คุณไม่เคยรู้เลย…: D
Ry-

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

2
รอยขีดข่วนความคิดเห็นของฉันข้างต้น: จริงdata != nullจะตรวจสอบทั้งสองnullและundefined( แต่ที่น่าสนใจเพียงnullและundefinedและไม่ค่า falsy อื่น ๆ )
bfavaretto

90

ใน JavaScript nullเป็นวัตถุแบบซิงเกิลพิเศษซึ่งมีประโยชน์สำหรับการส่งสัญญาณ "ไม่มีค่า" คุณสามารถทดสอบได้โดยการเปรียบเทียบและตามปกติใน JavaScript คุณควรใช้===โอเปอเรเตอร์เพื่อหลีกเลี่ยงการบีบบังคับประเภทที่สับสน:

var a = null;
alert(a === null); // true

@rynah พูดถึงว่า "undefined" ค่อนข้างสับสนใน JavaScript อย่างไรก็ตามจะปลอดภัยเสมอที่จะทดสอบว่าtypeof(x)สตริงนั้นเป็น "undefined" หรือไม่แม้ว่า "x" จะไม่ใช่ตัวแปรที่ประกาศไว้:

alert(typeof(x) === 'undefined'); // true

นอกจากนี้ตัวแปรอาจมี "ค่าที่ไม่ได้กำหนด" หากไม่ได้เตรียมข้อมูลเบื้องต้น

var y;
alert(typeof(y) === 'undefined'); // true

เช็คทั้งหมดของคุณควรมีลักษณะดังนี้:

if ((typeof(data) !== 'undefined') && (data !== null)) {
  // ...

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

function(data) {
  if ((data !== undefined) && (data !== null)) {
    // ...

ตัวอย่างนี้จะบอกว่า "ถ้าฟังก์ชั่นนั้นถูกเรียกด้วยอาร์กิวเมนต์ที่ถูกกำหนดและไม่เป็นโมฆะ ... "


5
ทำไมควรจะมีลักษณะเหมือนว่า แต่? != nullจะเป็นจริงสำหรับทุกค่ายกเว้นnullและundefinedและเรามั่นใจว่าจะประกาศตัวแปรนี้ typeofในสถานการณ์อื่นอาจเป็นอันตรายได้ - ถ้าคุณพิมพ์ชื่อตัวแปรผิด สิ่งนี้สามารถตรวจจับไม่ได้เป็นเวลานานเนื่องจากไม่มีข้อผิดพลาด
Ry-

@ maerics ดังนั้นถ้าฉันทำตามคำตอบของคุณอย่างถูกต้องในการตรวจสอบโมฆะเช่นสถานการณ์ข้างต้นคุณจะไม่ใช้!=เลยการเปรียบเทียบที่เข้มงวดเท่านั้น!==?
afsantos

@rynah: ฉันไม่เข้าใจว่าโซลูชันโดยรวมของ OP เพียงพอที่จะรู้หรือไม่ว่าการทดสอบแบบ null นั้นเหมาะสมหรือไม่
maerics

@afsantos: อันที่จริงฉันไม่คิดว่าค่า (ใด ๆ ) จะแปลงเป็นค่าว่าง อย่างไรก็ตามเป็นวิธีปฏิบัติที่ดีที่สุดในการใช้การเปรียบเทียบอย่างเข้มงวด ( ===) เว้นแต่คุณจะรู้ว่าคุณกำลังทำอะไรอยู่และต้องการเปรียบเทียบหลังจากการแปลง ( ==)
maerics

1
@Izkata: Drop ห้องสมุดใด ๆ undefinedที่พยายามที่จะกำหนด นอกจากนี้ Safari บน iPad จะไม่ทำเช่นนั้น delete window.undefinedคุณไม่สามารถแม้กระทั่ง
Ry-

10

ในกรณีของคุณใช้data==null(ซึ่งเป็นจริงเฉพาะสำหรับโมฆะและไม่ได้กำหนด - ในโฟกัสภาพที่สองในแถว / คอลัมน์ null- ไม่ได้กำหนด)

ที่นี่คุณมีทั้งหมด ( src ):

ถ้า

ป้อนคำอธิบายรูปภาพที่นี่

== (การปฏิเสธของมัน! = )

ป้อนคำอธิบายรูปภาพที่นี่

=== (การปฏิเสธของมัน! == )

ป้อนคำอธิบายรูปภาพที่นี่


8

ถาม:ฟังก์ชั่นถูกเรียกใช้โดยไม่มีข้อโต้แย้งจึงทำให้ข้อมูลเป็นตัวแปรที่ไม่ได้กำหนดและทำให้เกิดข้อผิดพลาดกับข้อมูล! = null

ตอบ:ใช่dataจะถูกตั้งค่าเป็นไม่ได้กำหนด ดูที่10.5 การประกาศการผูกมัดอินสแตนซ์ของสเป็ค แต่การเข้าถึงค่าที่ไม่ได้กำหนดจะไม่ทำให้เกิดข้อผิดพลาด คุณอาจสับสนกับการเข้าถึงตัวแปรที่ไม่ได้ประกาศในโหมดเข้มงวดซึ่งทำให้เกิดข้อผิดพลาด

ถาม:ฟังก์ชั่นนี้ถูกเรียกใช้เป็นพิเศษด้วย null (หรือไม่ได้กำหนด) เป็นอาร์กิวเมนต์ในกรณีที่ data! = null ได้ปกป้องโค้ดภายในการเรนเดอร์ && data! == undefined ไร้ประโยชน์

ถาม:ฟังก์ชั่นถูกเรียกใช้พร้อมอาร์กิวเมนต์ที่ไม่เป็นโมฆะซึ่งในกรณีนี้จะส่งผ่านข้อมูลทั้งสองเล็กน้อย! = null และ data! == undefined

ตอบ:ถูกต้อง โปรดทราบว่าการทดสอบต่อไปนี้เทียบเท่า:

data != null
data != undefined
data !== null && data !== undefined

ดูส่วนที่ 11.9.3 อัลกอริทึมการเปรียบเทียบความเท่าเทียมกันที่เป็นนามธรรมและส่วนที่ 11.9.6 อัลกอริทึมการเปรียบเทียบความเท่าเทียมกันอย่างเข้มงวดของสเป็ค


ฉันไม่ได้สับสนกับตัวแปรที่ไม่ได้ประกาศฉันไม่รู้จริงๆว่ามันทำงานอย่างไรเมื่อไม่มีข้อโต้แย้ง ผมเชื่อว่าจะไม่อยู่ที่ทุกคนแทนที่จะเป็นชุดdata undefinedฉันซาบซึ้งในความกระจ่างและการอ้างอิงเหล่านั้นช่วยให้ฉันเข้าใจในรายละเอียดที่ดีกว่าว่าการทำงานของทั้งสองมีความเท่าเทียมกันอย่างไร
afsantos

3

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

function (data) {
  if (data != null && data !== undefined) {
    // some code here
    // but what if data === false?
    // or data === '' - empty string?
  }
}

ทำอะไรแบบนี้:

function (data) {
  if (typeof data === 'string' && data.length) {
    // consume string here, it is here for sure
    // cleaner, it is obvious what type you expect
    // safer, less error prone due to implicit coercion
  } 
}

2

typeof foo === "undefined"ต่างจากfoo === undefinedอย่าสับสน typeof foo === "undefined"คือสิ่งที่คุณต้องการจริงๆ นอกจากนี้ยังใช้!==แทน!=

ดังนั้นคำสั่งสามารถเขียนเป็น

function (data) {
  if (typeof data !== "undefined" && data !== null) {
    // some code here
  }
}

แก้ไข:

คุณไม่สามารถใช้foo === undefinedสำหรับตัวแปรที่ไม่ได้ประกาศ

var t1;

if(typeof t1 === "undefined")
{
  alert("cp1");
}

if(t1 === undefined)
{
  alert("cp2");
}

if(typeof t2 === "undefined")
{
  alert("cp3");
}

if(t2 === undefined) // fails as t2 is never declared
{
  alert("cp4");
}

1
ตกลง แต่มีการประกาศตัวแปรในกรณีนี้ดังนั้นปัญหาคืออะไร
Ry-

โดยส่วนตัวแล้วฉันพบว่ามีfoo === undefinedอันตรายที่จะใช้ ทำให้รหัสของคุณล้มเหลวในสภาพเดียวกับที่คุณพยายามป้องกัน

ฉันกำลังพูดถึงอาร์กิวเมนต์ของฟังก์ชันที่เป็นปัญหา ดูความคิดเห็นอื่นของฉันด้วย
Ry-

1
ทำไมสิ่งนี้จึงถูกลดระดับลง‽ประโยคแรกนั้นเป็นความแตกต่างที่ถูกต้องและสำคัญ !
Izkata

1
@Izkata: เนื่องจากไม่มีคำอธิบายสำหรับคำสั่งเริ่มต้น foo === undefinedเป็นที่ยอมรับอย่างสมบูรณ์ในสถานการณ์ของ OP (สมมติundefinedว่าไม่ได้ถูกแทนที่) คำตอบยังล้มเหลวที่จะอธิบายว่าทำไม ควรจะใช้ในสถานที่ของ!== !=
Matt

1

วิธีง่ายๆในการทำแบบทดสอบของคุณคือ:

function (data) {
    if (data) { // check if null, undefined, empty ...
        // some code here
    }
}

5
นี่ไม่ใช่การทดสอบตามบริบทหรือไม่ ฉันหมายความว่าถ้าประเภทที่คาดหวังสำหรับdataเป็นสตริงการทดสอบนี้จะส่งกลับค่าเท็จในสตริงว่างซึ่งอาจหรืออาจจะไม่เหมาะสม (ฟังก์ชั่นอาจต้องการที่จะจัดการกับสตริงที่ว่างเปล่าในบางวิธี)
afsantos

5
ยกเว้นว่าหาก "ข้อมูล" มีค่า""หรือ0หรือNaN(หรืออื่น ๆ ) บล็อก "ถ้า" จะถูกข้าม; ซึ่งอาจจะใช่หรือไม่ใช่เจตนาของ OP
maerics

ขออภัย @afsantos ฉันไม่เห็นความคิดเห็นของคุณหากคุณต้องการที่จะได้รับข้อมูลเท็จเมื่อไม่ได้กำหนดเป็นโมฆะ ... ยกเว้นเมื่อวันที่ว่างเปล่าคุณจะต้องสร้างvar toTest = dataอื่น ๆ กับการทดสอบอื่น ๆ หลังจากคนแรกที่ชอบ: ถ้า (toTest == "") {// รหัสบางอย่างที่นี่}
Kadiri

-5
var a;
alert(a); //Value is undefined

var b = "Volvo"; 
alert(b); //Value is Volvo

var c = null;
alert(c); //Value is null

4
โปรดเพิ่มคำอธิบายเกี่ยวกับสิ่งที่ควรจะหมายถึง
Ry-

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