ใน JavaScript อันตรายแค่ไหนที่จะถือว่า undefined ไม่ได้ถูกเขียนทับ?


87

ทุกคนทุกคนเวลาที่กล่าวถึงการทดสอบกับundefined, ก็ออกมาชี้ว่าundefinedไม่ได้เป็นคำหลักดังนั้นมันอาจจะกำหนดให้"hello"ดังนั้นคุณควรใช้ typeof x == "undefined"แทน นี่ดูไร้สาระสำหรับฉัน คงไม่มีใครทำแบบนั้นและถ้าพวกเขาทำมันจะมีเหตุผลเพียงพอที่จะไม่ใช้รหัสใด ๆ ที่พวกเขาเขียน ... ใช่ไหม?

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

ใน C ++ ทุกคนตระหนักดีว่าการพูดถูกกฎหมาย#define true falseแต่ไม่มีใครเคยแนะนำให้คุณหลีกเลี่ยงtrueและใช้0 == 0แทน คุณคิดว่าคงไม่มีใครเป็นคนขี้เหวี่ยงมากพอที่จะทำเช่นนั้นและถ้าเป็นเช่นนั้นอย่าเชื่อรหัสของพวกเขาอีกเลย

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

ขอย้ำอีกครั้งว่าฉันไม่ได้ถามถึงวิธีการป้องกันจากการมอบหมายใหม่ที่ไม่ได้กำหนด ฉันเคยเห็นกลเม็ดเหล่านั้นเขียนถึง 100 ครั้งแล้ว ฉันกำลังถามว่าการไม่ใช้กลอุบายเหล่านั้นอันตรายแค่ไหน


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

1
ฉันคิดว่าข้อเท็จจริงทั้งหมดได้ระบุไว้ที่นี่แล้ว ดังนั้นสิ่งที่คุณพูดคือคุณต้องการคำตอบหรือความคิดเห็นแบบอัตนัยแทนซึ่งนำไปสู่ความไม่เห็นด้วยเท่านั้น นี่คือเหตุผลที่ไม่อนุญาตให้ใช้วลี "แนวทางปฏิบัติที่ดีที่สุด" ในชื่อคำถาม คุณเป็นคนเดียวที่สามารถรู้ได้ว่ามันอันตรายแค่ไหนในสถานการณ์ของคุณ และหากคุณกำลังเขียนไลบรารียอดนิยมโดยที่คุณไม่ได้ควบคุม 'ตัวแปร' ทั้งหมดฟังก์ชัน (ไม่ได้กำหนด) {} wrapper ดูเหมือนจะเป็นคำตอบที่ดีเยี่ยม ทำไมไม่ใช้และยอมรับคำตอบนั้น
shannon

4
ถ้าใครที่กังวลเกี่ยวกับคน Redefining undefinedคุณควรกังวลมากขึ้นเกี่ยวกับคน Redefining หรือXMLHttpRequest alertฟังก์ชันทั้งหมดที่เราใช้windowอาจได้รับการนิยามใหม่ และถ้าคุณกำลังกังวลเพียงเกี่ยวกับเพื่อนร่วมงานที่ทำมันโดยบังเอิญทำไมไม่ไว้วางใจพวกเขาจะทำอย่างไรwindow.addEventListener = "coolbeans"? คำตอบคือไม่ต้องกังวลใด ๆ หากมีคนฉีด JS เข้าไปในเพจของคุณโดยมีเจตนาร้าย พยายามป้องกันไม่ให้สิ่งนั้นเกิดขึ้นตั้งแต่แรก
Chris Middleton

คำตอบ:


57

ไม่ฉันไม่เคยมี ส่วนใหญ่เป็นเพราะฉันพัฒนาบนเบราว์เซอร์สมัยใหม่ซึ่งส่วนใหญ่เป็นไปตามมาตรฐาน ECMAScript 5 มาตรฐาน ES5 กำหนดว่าundefinedตอนนี้เป็นแบบอ่านอย่างเดียว หากคุณใช้โหมดเข้มงวด (คุณควร) ข้อผิดพลาดจะเกิดขึ้นหากคุณพยายามแก้ไขโดยไม่ได้ตั้งใจ

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

สิ่งที่คุณไม่ควรทำคือสร้างขอบเขตของคุณเองโดยไม่เปลี่ยนแปลงundefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

ค่าคงที่ไม่เป็นไร ยังคงไม่จำเป็น แต่ก็ดี

(function () {
    const undefined = void 0;
})();

คำสั่งแรกของคุณจะช่วยให้มั่นใจได้ว่าคุณจะไม่เขียนทับโดยไม่ได้ตั้งใจโดยไม่ได้ตั้งใจในขณะที่กำลังพัฒนาคำสั่งนั้นยังคงเป็นภัยคุกคามเดียวกันเมื่อทำงานกับรหัสอื่นบนคอมพิวเตอร์ไคลเอนต์
bennedich

1
@bennedich: ฉันรู้ว่าที่ผมบอกว่าผมไม่เคยทำงานเป็นปัญหานั้น แต่นี่คือสิ่งที่คุณควรทำ
Ry-

1
@bennedich คุณไม่มีโอกาสเหมือนกันที่จะเขียนทับตัวแปรอื่นโดยไม่ได้ตั้งใจหรือไม่?
Ates Goral

40

ไม่มีรหัสที่เหมาะสมจะทำสิ่งนั้นได้ แต่คุณไม่มีทางรู้ได้เลยว่านักพัฒนาที่เก่งกาจหรือปลั๊กอิน / ไลบรารี / สคริปต์ที่คุณใช้ทำอะไรอยู่ ในอีกด้านหนึ่งมันไม่น่าเป็นไปได้อย่างยิ่งและเบราว์เซอร์สมัยใหม่จะไม่อนุญาตให้เขียนทับundefinedเลยดังนั้นหากคุณใช้เบราว์เซอร์ดังกล่าวเพื่อการพัฒนาคุณจะสังเกตเห็นได้อย่างรวดเร็วว่ามีโค้ดใดพยายามเขียนทับหรือไม่


และแม้ว่าคุณจะไม่ได้ถาม แต่หลายคนอาจจะพบคำถามนี้เมื่อมองหาปัญหา "วิธีการป้องกันการกำหนดนิยามใหม่undefined" ที่พบบ่อยมากขึ้นดังนั้นฉันจะตอบว่า:

มีวิธีที่ดีมากในการใช้งานที่ไม่ได้กำหนดไว้ อย่างแท้จริงไม่undefinedว่าเบราว์เซอร์จะเก่าแค่ไหน:

(function(undefined) {
    // your code where undefined is undefined
})();

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

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

จากนั้นคุณสามารถมั่นใจได้ว่าภายในฟังก์ชันที่ไม่ระบุชื่อนั้นมีสิ่งต่อไปนี้เป็นจริง:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

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


2
คำชี้แจงของคุณเกี่ยวกับการxไม่ตั้งค่าเป็นค่าไม่เป็นความจริง (ดูjsfiddle.net/MgADz ) แต่มันไม่ได้กำหนดไว้จริงๆ(ดูjsfiddle.net/MgADz/1 )
Ry-

7
อีกครั้งหากใครบางคนบังเอิญพูดว่าundefined = someVariableนั่นเป็นจุดบกพร่องและคุณต้องการให้สิ่งต่างๆพัง อย่างน้อยฉันก็ทำ
Cosmologicon

2
ฉันได้ทำงานกับ codebase ที่มีสคริปต์ดั้งเดิมที่ย่อขนาดซึ่งเขียนทับโดยไม่ได้กำหนดเราไม่มีเวลาหรืองบประมาณในการเขียนสคริปต์ใหม่นี่เป็นตัวอย่างที่ต้องระบุ typeof x == "undefined" ซึ่งก็ไม่แปลกและอาจ นิสัยที่ดี
Damen TheSifter

2
ฉันสนใจว่าทำไมตัวอย่างทั้งหมดจึงใช้ "undefined" เป็นอาร์กิวเมนต์เพิ่มเติมในฟังก์ชัน แต่อาจมีสถานการณ์หากมีคนส่งพารามิเตอร์พิเศษ (กำหนด) โดย error และตรรกะทั้งหมดจะล้มเหลว ทำไมไม่ใช้บางอย่างเช่น function () {var _undef; if (someVal == _undef) {ทำบางอย่าง}};
Oleksandr_DJ

4
@Oleksandr_DJ แน่นอน Make up ค่าที่คุณรู้ว่าเป็นundefinedและกำหนดว่าจะundefinedอยู่ในขอบเขต อย่าundefinedเปิดทิ้งไว้ให้เขียนทับหากคุณส่งข้อโต้แย้ง "มากเกินไป" ที่เชิญชวนให้เกิดข้อผิดพลาดและเป็นรูปแบบที่ไม่มีการป้องกันโดยเนื้อแท้โดยเฉพาะอย่างยิ่งเมื่อLucero ชี้ให้เห็นว่ามีทางเลือกที่ง่ายมากในการตั้งรับundefinedค่าที่ในขอบเขต
ruffin

19

มีวิธีแก้ไขง่ายๆ: เปรียบเทียบกับvoid 0สิ่งที่ไม่ได้กำหนดไว้เสมอ

โปรดทราบว่าคุณควรหลีกเลี่ยง==เนื่องจากอาจบีบบังคับค่าต่างๆ ใช้===(และ!==) แทน

ที่กล่าวว่าตัวแปรที่ไม่ได้กำหนดอาจจะกำหนดจากข้อผิดพลาดถ้ามีคนเขียน=แทนเมื่อเปรียบเทียบกับบางสิ่งบางอย่าง==undefined


IMO นี่คือคำตอบที่ดีที่สุด
abhisekp

1
พิจารณาว่าfoo === void 0อาจอ่านไม่ราบรื่นfoo === undefinedและไม่เปลี่ยนรูปundefinedได้รับการสนับสนุนอย่างเต็มที่โดยเบราว์เซอร์ที่ทันสมัย (IE 9 +) ที่คุณสามารถดูในนี้ตารางการทำงานร่วมกัน
Daniel AR Werner

3

มีเพียงคุณเท่านั้นที่รู้ว่าคุณใช้รหัสอะไรจึงอันตรายเพียงใด คำถามนี้ไม่สามารถตอบได้ในแบบที่คุณได้ชี้แจงไว้ว่าต้องการคำตอบ

1) สร้างนโยบายของทีมไม่อนุญาตให้กำหนดใหม่ที่ไม่ได้กำหนดสงวนไว้สำหรับการใช้งานที่เป็นที่นิยมมากขึ้น สแกนรหัสที่มีอยู่ของคุณสำหรับการกำหนดด้านซ้ายที่ไม่ได้กำหนด

2) หากคุณไม่ได้ควบคุมสถานการณ์ทั้งหมดหากโค้ดของคุณถูกใช้นอกสถานการณ์ที่คุณหรือนโยบายของคุณควบคุมแสดงว่าคำตอบของคุณแตกต่างออกไปอย่างชัดเจน สแกนโค้ดที่ใช้สคริปต์ของคุณ Heck สแกนเว็บเพื่อหาสถิติของการมอบหมายงานด้านซ้ายที่ไม่ได้กำหนดหากคุณต้องการ แต่ฉันสงสัยว่านั่นเสร็จแล้วสำหรับคุณเพราะมันง่ายกว่าที่จะตอบคำถาม # 1 หรือ # 3 ที่นี่แทน

3) และหากคำตอบนั้นไม่ดีพออาจเป็นเพราะคุณต้องการคำตอบอื่นอีกครั้ง บางทีคุณกำลังเขียนไลบรารียอดนิยมที่จะใช้ภายในไฟร์วอลล์ขององค์กรและคุณไม่มีสิทธิ์เข้าถึงรหัสการโทร จากนั้นใช้หนึ่งในคำตอบอื่น ๆ ที่นี่ สังเกตว่าไลบรารี jQuery ที่เป็นที่นิยมใช้การห่อหุ้มเสียงและเริ่มต้น:

(function( window, undefined ) {

มีเพียงคุณเท่านั้นที่สามารถตอบคำถามของคุณในแบบที่คุณต้องการ มีอะไรจะพูดอีก?

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


3

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

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


2

คุณสามารถใช้undefinedในรหัสของคุณเมื่อการเข้ารหัสสำหรับเบราว์เซอร์ที่สนับสนุน ECMAScript 5.1 มันเป็นไม่เปลี่ยนรูปตามข้อกำหนดของภาษา

ยังเห็นนี้ตารางการทำงานร่วมกันหรือนี้ caniuse ECMAScript 5จะเห็นว่าทุกเบราว์เซอร์ที่ทันสมัย (IE 9+) undefinedได้ดำเนินการเปลี่ยนรูป



0

ก่อนอื่นหากโค้ดของคุณแตกอาจไม่ใช่เพราะนักพัฒนารายอื่น "พยายามกระตุก" อย่างที่คุณวางไว้

เป็นเรื่องจริงที่undefinedไม่ใช่คีย์เวิร์ด แต่เป็นบรรพกาลระดับโลก. มีวัตถุประสงค์เพื่อใช้ในลักษณะนี้ (ดู "ไม่ได้กำหนด" ที่ developer.mozilla.org ):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

ทางเลือกทั่วไปสำหรับสิ่งนั้น (จากMDN ) และในความคิดของฉันวิธีที่ดีกว่าคือ:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

ซึ่งมีข้อดีอยู่สองประการข้อที่ชัดเจน (จากความคิดเห็น) คือมันไม่ได้ทำให้เกิดข้อยกเว้นเมื่อไม่ได้ประกาศ x นอกจากนี้ยังเป็นที่น่าสังเกตว่า MDN ยังชี้ให้เห็นว่ามันเป็นสิ่งสำคัญที่จะใช้===มากกว่า==ในกรณีแรกเนื่องจาก:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

นี่เป็นอีกเหตุผลหนึ่งที่มักถูกมองข้ามว่าทำไมจึงควรใช้ทางเลือกที่สองในทุกกรณี

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


1
"ซึ่งมีข้อดีอยู่สองประการข้อที่ชัดเจนคือไม่ทำให้เกิดข้อยกเว้นเมื่อไม่ได้ประกาศ x" ให้ฉันได้รับตรงนี้. คุณคิดว่ามันเป็นไฟล์เพิกเฉยต่อข้อยกเว้นที่เกิดขึ้นเมื่อคุณใช้ตัวแปรที่ไม่ได้ประกาศข้อดีหรือไม่? ดูเหมือนว่าจะเกิดข้อผิดพลาดได้ง่าย คุณอธิบายได้ไหมว่าทำไมคุณถึงคิดว่านั่นไม่ใช่ข้อเสียที่น่ากลัว?
Cosmologicon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.