ตัวแปร === ไม่ได้กำหนดกับประเภทตัวแปร ===“ ไม่ได้กำหนด”


300

jQuery หลักแนวทางรูปแบบการแนะนำสองวิธีที่แตกต่างกันเพื่อตรวจสอบว่าตัวแปรที่ถูกกำหนดไว้

  • ตัวแปรทั่วโลก: typeof variable === "undefined"
  • ตัวแปรท้องถิ่น: variable === undefined
  • คุณสมบัติ: object.prop === undefined

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


ฉันไม่สามารถตอบคำถามได้ว่าทำไม JQuery จึงใช้ทั้งสองวิธี แต่ Javascript มีนิสัยใจคอที่น่าสนใจซึ่งหมายความว่าสองสิ่งนี้ต่างกันอย่างละเอียด ไม่ควรใช้เวลาส่วนใหญ่ (เช่นถ้ารหัสของคุณมีสติ) แต่มีความแตกต่าง: ดูที่นี่สำหรับบทความ - wtfjs.com/2010/02/15/undefined-is-mutable
Spudley

2
เป็น @Struppi ชี้ให้เห็นฟังก์ชั่นนอกสุดของ jQuery มีอาร์กิวเมนต์ที่ไม่ได้กำหนด ภายใน jQuery foo === undefinedกำลังตรวจสอบกับสำเนาโลคัลของ undefined แทน global (window.undefined) ซึ่งอาจถูกแก้ไขโดยโค้ดบ้า ความจริงที่ว่าการไม่ได้นิยามนั้นไม่แน่นอนนั้นเป็นสิ่งที่ควรค่าแก่การสังเกตและฉันดีใจที่คุณทำ (+1)
Patrick McElhaney

1
ลิงค์ปัจจุบันสำหรับบทความนั้นคือwtfjs.com/wtfs/2010-02-15-undefined-is-mutable
enigment

คำตอบ:


366

สำหรับตัวแปรที่ไม่ได้ประกาศtypeof fooจะกลับตัวอักษรสตริง"undefined"ในขณะที่การตรวจสอบตัวตนfoo === undefinedจะเรียกข้อผิดพลาด"foo ไม่ได้ถูกกำหนด"

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


3
@goreSplatter คุณไม่สามารถลบได้ตอนนี้ :-) มันยากที่จะเลือก แต่วิธีที่คำถามนั้นเป็นคำพูดคำตอบนี้เหมาะกว่า ทุกคนที่มีความสนใจเกี่ยวกับวิธีการทำงานที่ไม่ได้กำหนดโดยทั่วไป (เหมือนฉัน) ควรดูคำตอบอื่น ๆ โดยเฉพาะอย่างยิ่ง @ Tim
Patrick McElhaney

4
ฉันจะเพิ่มเครื่องหมายคำพูด ( typeof foo; // -> "undefined") undefinedเพื่อเน้นว่ามันเป็นสตริงและไม่คุ้มค่าดั้งเดิม
c24w

117

ฉันต้องการใช้typeof foo === "undefined"ทุกที่ ที่ไม่เคยผิดพลาด

ฉันคิดว่าเหตุผลที่ jQuery แนะนำวิธีที่แตกต่างกันสองวิธีคือพวกเขากำหนดundefinedตัวแปรของตัวเองภายในฟังก์ชั่นที่รหัส jQuery อาศัยอยู่ดังนั้นภายในฟังก์ชั่นundefinedนั้นปลอดภัยจากการดัดแปลงจากภายนอก ฉันยังนึกภาพว่าบางคนได้เปรียบเทียบวิธีที่แตกต่างกันสองแบบและค้นพบว่าfoo === undefinedมันเร็วกว่าและคิดว่าเป็นวิธีที่จะไป [อัพเดท: ตามที่ระบุไว้ในความคิดเห็นการเปรียบเทียบกับundefinedก็สั้นลงเล็กน้อยซึ่งอาจเป็นข้อพิจารณา] อย่างไรก็ตามการได้รับในสถานการณ์จริงจะไม่สำคัญมาก: การตรวจสอบนี้จะไม่เคยเป็นคอขวดใด ๆ คุณสูญเสียความสำคัญ: การประเมินคุณสมบัติของวัตถุโฮสต์สำหรับการเปรียบเทียบสามารถโยนข้อผิดพลาดในขณะที่typeof ตรวจสอบจะไม่

ตัวอย่างเช่นต่อไปนี้ใช้ใน IE เพื่อแยกวิเคราะห์ XML:

var x = new ActiveXObject("Microsoft.XMLDOM");

วิธีตรวจสอบว่ามีloadXMLวิธีการอย่างปลอดภัยหรือไม่:

typeof x.loadXML === "undefined"; // Returns false

ในทางกลับกัน:

x.loadXML === undefined; // Throws an error

UPDATE

ประโยชน์อีกประการหนึ่งของtypeofการตรวจสอบว่าฉันลืมที่จะพูดถึงก็คือว่ามันยังทำงานร่วมกับตัวแปรที่ไม่ได้ประกาศที่ตรวจสอบไม่ได้และในความเป็นจริงพ่นfoo === undefined ReferenceErrorขอบคุณ @LinusKleen ที่เตือนฉัน ตัวอย่างเช่น:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

บรรทัดล่างสุด: ใช้typeofเช็คเสมอ


10
ขอบคุณทิม ประเด็นของคุณเกี่ยวกับประสิทธิภาพนั้นสมเหตุสมผลดี ทีมงาน jQuery มีความกังวลมากขึ้นเกี่ยวกับผลกระทบต่อขนาดไฟล์ foo === undefinedเมื่อย่อเล็กสุดอาจเป็นสิ่งที่ต้องการf===uในขณะที่typeof foo === "undefined"สามารถลดลงtypeof f==="undefined"ได้เท่านั้น
Patrick McElhaney

1
คุณสามารถกำหนดvar u = "undefined"และลดขนาดได้typeof f==uซึ่งจะปรับปรุงสิ่งต่าง ๆ แต่ยังคงมีขนาดใหญ่กว่า
ทิมดาวน์

5
จุดที่ดี แต่ฉันไม่แน่ใจว่าความปลอดภัยของtypeofตัวแปรที่ไม่ได้ประกาศเป็นข้อได้เปรียบ หากมีสิ่งใดที่ช่วยให้พิมพ์ผิดได้ง่ายขึ้นและฉันไม่เห็นว่าคุณต้องการตรวจสอบชนิดของตัวแปรที่ไม่ได้ประกาศ
David Tang

2
@ Box9: ฉันสามารถจินตนาการใช้ในห้องสมุดเพื่อตรวจสอบการปรากฏตัวของห้องสมุดอื่น
Tim Down

2
@ jontro: นั่นเป็นเหตุผลหนึ่งที่ไม่ควรใช้ JSLint
Tim Down

29

อีกเหตุผลหนึ่งที่ใช้ประเภทของตัวแปร: undefinedสามารถนิยามใหม่ได้

undefined = "foo";
var variable = "foo";
if (variable === undefined)
  console.log("eh, what?!");

ผลลัพธ์ของtypeof variable ไม่สามารถ

อัปเดต : โปรดทราบว่านี่ไม่ใช่กรณีใน ES5 ที่นั่นโกลบอลundefinedเป็นคุณสมบัติที่ไม่สามารถกำหนดค่าได้และไม่สามารถเขียนได้:

15.1.1 คุณสมบัติค่าของวัตถุส่วนกลาง
[... ]
15.1.1.3 ไม่ได้กำหนด
ค่าของundefinedจะไม่ได้กำหนด (ดู 8.1) คุณสมบัตินี้มีแอตทริบิวต์
{[[เขียนได้]]: false, [[นับจำนวน]]: false, [[กำหนดค่าได้]]: false}

แต่ตัวแปรเงายังสามารถเงาได้:

(function() {
  var undefined = "foo";
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})()

หรือพารามิเตอร์:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")

17
ไม่สามารถนิยามใหม่ใน ES5
Ry-

6
undefinedไม่สามารถกำหนดคุณสมบัติโกลบอลใหม่ได้ใน ES5 แต่ยังสามารถแชโดว์ด้วยตัวแปรโลคอลได้ void 0สั้นกว่าและปลอดภัยกว่า
Oriol

7

เพราะundefinedไม่ได้ประกาศเสมอ แต่ jQuery ประกาศundefinedในฟังก์ชั่นหลัก ดังนั้นพวกเขาจึงใช้undefinedค่าความปลอดภัยภายใน แต่ภายนอกพวกเขาใช้typeofสไตล์เพื่อความปลอดภัย



1

สำหรับตัวแปรในท้องถิ่นการตรวจสอบด้วยlocalVar === undefinedจะใช้งานได้เนื่องจากจะต้องมีการกำหนดไว้ในที่ใดที่หนึ่งภายในขอบเขตมิฉะนั้นจะไม่ถูกพิจารณาว่าเป็นแบบโลคัล

สำหรับตัวแปรที่ไม่ใช่แบบโลคัลและไม่ได้กำหนดไว้ทุกที่การตรวจสอบsomeVar === undefinedจะเกิดข้อยกเว้น: Uncaught ReferenceError: j ไม่ได้ถูกกำหนดไว้

นี่คือรหัสบางส่วนที่จะอธิบายสิ่งที่ฉันพูดด้านบน โปรดให้ความสนใจที่จะ inline ความคิดเห็นเพื่อความชัดเจนต่อไป

function f (x) {
    if (x === undefined) console.log('x is undefined [x === undefined].');
    else console.log('x is not undefined [x === undefined.]');

    if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].');
    else console.log('x is not undefined [typeof(x) === \'undefined\'].');

    // This will throw exception because what the hell is j? It is nowhere to be found.
    try
    {
        if (j === undefined) console.log('j is undefined [j === undefined].');
        else console.log('j is not undefined [j === undefined].');
    }
    catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');}

    // However this will not throw exception
    if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.');
    else console.log('j is not undefined [typeof(x) === \'undefined\'].');
};

หากเราเรียกรหัสข้างต้นดังนี้:

f();

ผลลัพธ์จะเป็นดังนี้:

x is undefined [x === undefined].
x is undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

หากเราเรียกรหัสข้างต้นเช่นนี้ (มีค่าใด ๆ จริง):

f(null); 
f(1);

ผลลัพธ์จะเป็น:

x is not undefined [x === undefined].
x is not undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

เมื่อคุณทำเครื่องหมายเช่นนี้: typeof x === 'undefined'คุณต้องถามสิ่งนี้เป็นหลัก: โปรดตรวจสอบว่าตัวแปรนั้นxมีอยู่ (ได้ถูกกำหนดไว้แล้ว) ที่ใดที่หนึ่งในซอร์สโค้ด (มากหรือน้อย). หากคุณรู้จัก C # หรือ Java การตรวจสอบประเภทนี้จะไม่เกิดขึ้นเพราะหากไม่มีอยู่จะไม่มีการรวบรวม

<== Fiddle Me ==>


1

สรุป:

เมื่ออยู่ในขอบเขตทั่วโลกเราต้องการกลับจริงถ้าตัวแปรไม่ได้ประกาศหรือมีค่าundefined:

var globalVar1;

// This variable is declared, but not defined and thus has the value undefined
console.log(globalVar1 === undefined);

// This variable is not declared and thus will throw a referenceError
console.log(globalVar2 === undefined);

เพราะในขอบเขตทั่วโลกเราไม่แน่ใจ 100% ว่ามีการประกาศตัวแปรหรือไม่นี่อาจทำให้เรามีข้ออ้างอิงอ้างอิง เมื่อเราใช้typeofโอเปอเรเตอร์กับตัวแปรที่ไม่รู้จักเราจะไม่ได้รับปัญหานี้เมื่อไม่ประกาศตัวแปร:

var globalVar1;

console.log(typeof globalVar1 === 'undefined');
console.log(typeof globalVar2 === 'undefined');

นี่เป็นเพราะความจริงที่ว่าtypeofผู้ประกอบการส่งกลับสตริงundefinedเมื่อตัวแปรไม่ได้ประกาศหรือในปัจจุบันถือค่าundefinedซึ่งเป็นสิ่งที่เราต้องการ


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

var obj = {};

console.log(obj.myProp === undefined);


-5

typeof a === 'undefined'เร็วกว่านั้นa === 'undefined'ประมาณ 2 เท่าบนโหนด v6.9.1


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