“ var FOO = FOO || คืออะไร {}” (กำหนดตัวแปรหรือวัตถุว่างให้กับตัวแปรนั้น) หมายถึงใน Javascript?


99

เมื่อดูซอร์สโค้ดออนไลน์ฉันพบสิ่งนี้ที่ด้านบนของไฟล์ต้นฉบับหลาย ๆ ไฟล์

var FOO = FOO || {};
FOO.Bar = …;

แต่ฉันไม่รู้ว่า|| {}จะทำอย่างไร

ฉันรู้ว่า{}มีค่าเท่ากับnew Object()และฉันคิดว่า||มีไว้สำหรับบางสิ่งเช่น "ถ้ามีอยู่แล้วให้ใช้ค่าอื่นให้ใช้วัตถุใหม่

เหตุใดฉันจึงเห็นสิ่งนี้ที่ด้านบนของไฟล์ต้นฉบับ


หมายเหตุ: คำถามนี้ได้รับการแก้ไขเพื่อแสดงว่านี่เป็นรูปแบบโค้ดที่พบเห็นได้ทั่วไปที่ด้านบนของซอร์สไฟล์ Javascript
Robert Harvey

คำตอบ:


152

การคาดเดาเจตนาของคุณ|| {}ค่อนข้างใกล้เคียง

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

เหตุผลที่ว่าทำไมมันใช้เป็นเพื่อที่ว่าถ้าคุณมีสอง (หรือมากกว่า) ไฟล์:

var MY_NAMESPACE = MY_NAMESPACE || {};
MY_NAMESPACE.func1 = {
}

และ

var MY_NAMESPACE = MY_NAMESPACE || {};
MY_NAMESPACE.func2 = {
}

ซึ่งทั้งสองใช้เนมสเปซเดียวกันซึ่งไม่สำคัญว่าจะโหลดไฟล์ทั้งสองตามลำดับใดคุณยังคงได้รับfunc1และfunc2กำหนดอย่างถูกต้องภายในMY_NAMESPACEออบเจ็กต์อย่างถูกต้อง

ไฟล์แรกที่โหลดจะสร้างMY_NAMESPACEอ็อบเจ็กต์เริ่มต้นและไฟล์ที่โหลดในภายหลังจะเพิ่มอ็อบเจ็กต์

นอกจากนี้ยังช่วยให้สามารถโหลดสคริปต์แบบอะซิงโครนัสที่ใช้เนมสเปซเดียวกันซึ่งสามารถปรับปรุงเวลาในการโหลดหน้าเว็บได้ หาก<script>แท็กมีdeferชุดแอตทริบิวต์คุณไม่สามารถทราบได้ว่าจะตีความลำดับใดดังนั้นตามที่อธิบายไว้ข้างต้นนี้จะช่วยแก้ปัญหานั้นได้เช่นกัน


2
ในกรณีนี้มีไฟล์ js สองไฟล์ที่มีการประกาศเดียวกันในตอนต้นขอบคุณมาก!
Ricardo Sanchez

41
+1 สำหรับการอ่านระหว่างบรรทัดและอธิบายเหตุผลในการทำ เป็นเรื่องดีเสมอเมื่อมีคนให้คำตอบที่ผู้ใช้ต้องการจริง ๆไม่ใช่แค่คำตอบที่เขาขอ :)
Spudley

1
ฉันอยากจะบอกว่ามันเป็น # ifndef / # define สำหรับ javascript :)
Darren Kopp

1
||ยังมีประโยชน์มากเมื่อคุณต้องการระบุอาร์กิวเมนต์ที่เป็นทางเลือกและเริ่มต้นให้เป็นค่าเริ่มต้นหากไม่ได้ระบุไว้:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
crazy2be

1
@ crazy2be ที่ไม่ทำงานถ้าเริ่มต้นคือ truthy แต่ค่า falsey นอกจากนี้ยังมีกฎหมายตั้งแต่||ผู้ประกอบการไม่สามารถบอกได้จากundefined falsey
Alnitak

22
var AEROTWIST = AEROTWIST || {};

โดยทั่วไปบรรทัดนี้จะบอกว่าตั้งค่าAEROTWISTตัวแปรเป็นค่าของAEROTWISTตัวแปรหรือตั้งค่าเป็นวัตถุว่าง

ท่อคู่||คือคำสั่ง OR และส่วนที่สองของ OR จะถูกดำเนินการก็ต่อเมื่อส่วนแรกส่งคืนค่าเท็จ

ดังนั้นหากAEROTWISTมีค่าอยู่แล้วก็จะเก็บเป็นค่านั้น แต่ถ้ายังไม่ได้ตั้งค่ามาก่อนก็จะตั้งค่าเป็นวัตถุว่าง

โดยพื้นฐานแล้วจะเหมือนกับการพูดสิ่งนี้:

if(!AEROTWIST) {var AEROTWIST={};}

หวังว่าจะช่วยได้


1
จริงๆแล้วขอบเขตจะใช้ได้ดีในตัวอย่างสุดท้ายของคุณเพราะJS ไม่มีขอบเขตการบล็อก
Alnitak

@Alnitak - ฉันใช่แล้ว; ช่วงนี้ฉันทำงานกับการปิดตัวมากเกินไปและลืมพื้นฐานไปแล้ว ฉันจะแก้ไขคำตอบ
Spudley

7

มีสองส่วนหลักที่var FOO = FOO || {};ครอบคลุม

# 1 การป้องกันการลบล้าง

FOOลองนึกภาพคุณต้องแยกรหัสของคุณในช่วงหลายไฟล์และเพื่อนร่วมงานของคุณนอกจากนี้ยังมีการทำงานเกี่ยวกับวัตถุที่เรียกว่า จากนั้นอาจนำไปสู่กรณีที่มีผู้กำหนดFOOและกำหนดฟังก์ชันการทำงานให้แล้ว (เช่นskateboardฟังก์ชัน) จากนั้นคุณจะลบล้างหากคุณไม่ได้ตรวจสอบว่ามีอยู่แล้วหรือไม่

กรณีที่มีปัญหา:

// Definition of co-worker "Bart" in "bart.js"
var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};

// Definition of co-worker "Homer" in "homer.js"
var FOO = {};

FOO.donut = function() {
  alert('I like donuts!');
};

ในกรณีนี้skateboardฟังก์ชันจะหายไปหากคุณโหลดไฟล์ JavaScript homer.jsหลังจากbart.jsใน HTML ของคุณเนื่องจากโฮเมอร์กำหนดFOOอ็อบเจ็กต์ใหม่(และแทนที่อ็อบเจ็กต์ที่มีอยู่จาก Bart) ดังนั้นจึงรู้เฉพาะเกี่ยวกับdonutฟังก์ชันเท่านั้น

ดังนั้นคุณต้องใช้var FOO = FOO || {};ซึ่งหมายความว่า "FOO จะถูกกำหนดให้กับ FOO (ถ้ามีอยู่แล้ว) หรือวัตถุเปล่าใหม่ (หากไม่มี FOO อยู่แล้ว)

วิธีการแก้:

var FOO = FOO || {};

// Definition of co-worker Bart in bart.js
FOO.skateboard = function() {
  alert('I like skateboarding!');
};

// Definition of co-worker Homer in homer.js
var FOO = FOO || {};

FOO.donut = function() {
  alert('I like donuts!');
};

เนื่องจากขณะนี้บาร์ตและโฮเมอร์กำลังตรวจสอบการมีอยู่ของFOOก่อนที่จะกำหนดวิธีการของพวกเขาคุณสามารถโหลดbart.jsและhomer.jsเรียงลำดับใด ๆ โดยไม่ต้องแทนที่วิธีการของกันและกัน (หากมีชื่อต่างกัน) ดังนั้นคุณจะได้รับFOOวัตถุที่มีวิธีการskateboardและdonut(เย้!)

# 2 การกำหนดวัตถุใหม่

หากคุณได้อ่านตัวอย่างแรกตอนนี้คุณมีจุดประสงค์ของไฟล์|| {}.

เนื่องจากถ้าไม่มีFOOวัตถุอยู่แล้ว OR-case จะทำงานและสร้างวัตถุใหม่ขึ้นมาดังนั้นคุณจึงสามารถกำหนดฟังก์ชันให้กับมันได้ ชอบ:

var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};

6

การใช้งานทั่วไปสำหรับ || คือการตั้งค่าเริ่มต้นสำหรับพารามิเตอร์ฟังก์ชันที่ไม่ได้กำหนดด้วย:

function display(a) {
  a = a || 'default'; // here we set the default value of a to be 'default'
  console.log(a);
}

// we call display without providing a parameter
display(); // this will log 'default'
display('test'); // this will log 'test' to the console

สิ่งที่เทียบเท่าในการเขียนโปรแกรมอื่น ๆ มักจะเป็น:

function display(a = 'default') {
  // ...
}

คุณไม่จำเป็นต้องvarอยู่ในด้านหน้าของa, aเข้าสู่บริบทการดำเนินการการทำงานในฐานะที่เป็นพารามิเตอร์ที่เป็นทางการจึงจะมีการประกาศแล้ว
FabrícioMatté

3

หากไม่มีค่าใน AEROTWIST หรือเป็นโมฆะหรือไม่ได้กำหนดค่าที่กำหนดให้กับ AEROTWIST ใหม่จะเป็น {} (วัตถุเปล่า)


1

ตัว||ดำเนินการรับค่าสองค่า:

a || b

ถ้าเป็นtruthyaก็จะกลับ bมิฉะนั้นก็จะกลับ

ค่า falsy มีnull, undefined, 0, "", และNaN falseค่าที่แท้จริงคือทุกสิ่งทุกอย่าง

ดังนั้นหากaยังไม่ได้รับการตั้งค่า (เป็นundefined) bก็จะกลับ


ฉันไม่แน่ใจว่าความจริงและความเท็จควรถูกทำให้เป็นจริง สนุก แต่ไม่ได้มาตรฐาน :-)
Orbling

4
@Orbling มักใช้พูดถึงค่าดังกล่าวใน JS
Alnitak

+1 เพื่ออธิบายตัวดำเนินการอย่างถูกต้องเนื่องจากไม่ใช่ตัวดำเนินการเชิงตรรกะ บางครั้งเรียกว่า "ตัวดำเนินการเริ่มต้น"
Tim Büthe

@Tim ความแตกต่างเพียงอย่างเดียวระหว่าง||ใน JS (และ Perl) กับเวอร์ชันใน C, C ++ และ Java คือ JS ไม่ส่งผลลัพธ์เป็นบูลีน มันยังคงเป็นตัวดำเนินการทางตรรกะ
Alnitak

@Alnitak: อาจเป็นเพราะภูมิหลังที่ไม่เป็นมืออาชีพของนักพัฒนา JS ในอดีต
Orbling

-1

โปรดสังเกตว่าใน IE บางเวอร์ชันรหัสนี้จะไม่ทำงานตามที่คาดไว้ เนื่องจากvarตัวแปรจะถูกกำหนดและกำหนดใหม่ดังนั้นหากฉันจำปัญหาได้ถูกต้องคุณจะมีวัตถุใหม่อยู่เสมอ ที่ควรแก้ไขปัญหา:

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