ประโยชน์ของฟังก์ชั่นที่ไม่มีพารามิเตอร์ซึ่งเรียกเฉพาะฟังก์ชั่นอื่นคืออะไร


21

บทช่วยสอน (สำหรับ Javascript) ฉันขอแนะนำให้เราเขียนฟังก์ชั่นแบบนี้:

function sayHello() {
   //Some comments explaining the next line
   window.alert("Hello");
}

นอกเหนือจากความงุนงงจะมีประโยชน์ในการเขียนสิ่งนี้ในชีวิตจริง? ถ้าเป็นเช่นนั้นประโยชน์คืออะไร?


14
มันอาจเป็นเพียงการพยายามแสดงวิธีการกำหนดฟังก์ชั่นของคุณเอง
Doval

4
ฉันจะไม่เขียนโค้ดในลักษณะที่ทำให้งงงวย - โค้ดสำหรับให้โปรแกรมเมอร์อ่านได้ง่ายไม่ใช่วิธีอื่น ใช้ obfuscater สำหรับ obfuscation
rhughes

32
ประโยชน์คือว่ามันล้อมฟังก์ชั่นที่มีพารามิเตอร์ วิธีนี้หากคุณต้องการให้แอปของคุณเป็นภาษาสเปนในภายหลังคุณจะต้องเปลี่ยน "Hello" เป็น "Ola" ในที่เดียว
Pieter B

9
@PieterB จริง ๆ แล้ว "Hola"
rev

29
@PieterB - และหากคุณพบว่าคุณสะกดคำว่า "Hola" คุณต้องแก้ไขมันในที่เดียว
Daniel R Hicks

คำตอบ:


60

โปรดให้อภัยความจำของฉันหากฉันมีสิ่งที่ไม่ถูกต้อง ... จาวาสคริปต์ไม่ใช่ภาษาการใช้งานที่ฉันต้องการ

มีสาเหตุหลายประการที่ทำให้ใครอยากจะไม่มีฟังก์ชั่นหาเรื่องห่อการเรียกฟังก์ชั่นอื่น ในขณะที่เรียกง่ายๆที่จะเป็นสิ่งที่คุณสามารถจินตนาการเพียงแทนที่จะเรียกโดยตรงแทนwindow.alert("Hello");sayHello()

แต่ถ้ามีมากกว่านั้นล่ะ คุณมีสถานที่มากมายที่คุณต้องการโทรหาsayHello()และเขียนwindow.alert("Hello");แทน window.alert("Hello, it is now " + new Date())ตอนนี้คุณต้องการที่จะทำ หากคุณห่อทุกสายเหล่านั้นในขณะที่sayHello()คุณเปลี่ยนมันที่เดียว ถ้าคุณไม่ทำคุณเปลี่ยนมันในหลาย ๆ ที่ สัมผัสเกี่ยวกับเรื่องนี้จะไม่ทำซ้ำตัวเอง คุณทำเพราะคุณไม่ต้องการที่จะทำมันอีกหลายสิบครั้งในอนาคต

ฉันทำงานกับไลบรารี่ i18n / l10nในอดีตที่ใช้ฟังก์ชั่นในการแปลข้อความฝั่งไคลเอ็นต์ พิจารณาsayHello()ฟังก์ชั่น คุณสามารถพิมพ์ออกมาholaเมื่อผู้ใช้แปลเป็นภาษาสเปน สิ่งนี้อาจมีลักษณะเช่น:

function sayHello() {
  var language = window.navigator.userLanguage || window.navigator.language;
  if(language === 'es') { window.alert('Hola'); }
   else { window.alert("Hello"); }
}

แม้ว่านี่จะไม่ใช่วิธีการทำงานของห้องสมุด มีชุดไฟล์ที่ดูเหมือน:

# English file
greeting = hello
# Spanish file
greeting = hola

จากนั้นไลบรารีจะตรวจจับการตั้งค่าภาษาของเบราว์เซอร์จากนั้นสร้างฟังก์ชันแบบไดนามิกด้วยการแปลที่เหมาะสมเป็นค่าส่งคืนสำหรับการเรียกใช้ฟังก์ชัน no-arguemnt ตามไฟล์การแปลที่เหมาะสม

ฉันยังไม่พอที่จะบอกว่าดีหรือไม่ดีจาวาสคริปต์ coder ... แค่ว่ามันและสามารถมองได้ว่าเป็นแนวทางที่เป็นไปได้

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

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


3
window.alertมักจะถูกใช้เป็นตัวยึดตำแหน่งในระหว่างการพัฒนาจนกว่า modal / ป๊อปอัปที่ดีสามารถออกแบบ / นำมาใช้ดังนั้นเช่นเดียวกับปัญหาภาษาก็สามารถเปลี่ยนได้ง่ายขึ้นมาก หรือถ้าคุณมีอยู่แล้วการออกแบบปรับปรุงไม่กี่ปีข้างหน้าบรรทัดอาจต้องการการเปลี่ยนแปลงที่คล้ายกัน
Izkata

34

ฉันคิดว่ามันมีประโยชน์ในบางครั้งสำหรับการซ่อนการใช้งาน

 function sayHello() {
  window.alert("Hello");
 }

และสิ่งนี้จะให้ความยืดหยุ่นแก่คุณในการเปลี่ยนแปลงในภายหลัง

 function sayHello() {
  console.log("Hello");
 }

19

นอกเหนือจากความงุนงงจะมีประโยชน์ในการเขียนสิ่งนี้ในชีวิตจริง? ถ้าเป็นเช่นนั้นประโยชน์คืออะไร?

  • การรวมศูนย์: แม้ว่าการใช้งานจะมีความยาวบรรทัดเดียว แต่ถ้าเป็นบรรทัดที่มีการเปลี่ยนแปลงบ่อยครั้งคุณอาจต้องการเปลี่ยนในที่เดียวมากกว่าที่ใดก็ตามที่มีการเรียกว่าเฮลโล

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

  • ปฏิบัติตามสัญญา: รหัสลูกค้าอาจคาดหวังโมดูลที่มีฟังก์ชั่น sayHello ในกรณีนี้แม้ว่าจะเป็นเรื่องเล็กน้อยฟังก์ชั่นจะต้องมี

  • ความสอดคล้องของระดับนามธรรม: หากรหัสลูกค้าใช้การดำเนินงานระดับสูงคุณสามารถเขียนรหัสลูกค้าในรูปแบบของ 'sayHello, sayBye' และฟังก์ชั่น 'sayXXX' อื่นแทนวัตถุหน้าต่าง Infact ในรหัสลูกค้าคุณอาจไม่ต้องการที่จะรู้ว่ามีสิ่งเช่นวัตถุ 'หน้าต่าง'


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

3
เหตุผลอื่นดี แต่ +1 สำหรับกล่าวถึงระดับนามธรรม การใช้ abstractions ที่ชัดเจนและชื่อฟังก์ชันที่ดีสามารถทำให้อ่านและดูแลโค้ดเก่าได้ง่ายขึ้น ณ จุดที่มีการเรียกใช้ sayHello () คุณไม่จำเป็นต้องกังวลเกี่ยวกับวิธีการนำไปใช้งานคุณเพียงต้องการเข้าใจว่าเจตนาของรหัสบรรทัดนี้คืออะไร และชื่อฟังก์ชั่นอย่าง sayHello () ทำให้ชัดเจน
kkrambo

+1 สำหรับการกล่าวถึงระดับ abstraction: มันสามารถเกิดขึ้นได้ว่าการใช้งานฟังก์ชันที่ระดับ abstraction หนึ่งประกอบด้วยการเรียกหนึ่งครั้งไปยังฟังก์ชันอื่นของระดับ abstraction ที่ต่ำกว่า แล้วอะไรล่ะ
Giorgio

7

น่าทึ่งที่คนอื่นไม่ได้พูดถึงการทดสอบ

บรรทัด "ที่พันแล้ว" ที่คุณเลือกwindow.alert('hello')เป็นตัวอย่างที่สมบูรณ์แบบของเรื่องนี้ อะไรก็ตามที่เกี่ยวข้องกับwindowวัตถุนั้นช่างเจ็บปวดจริงๆที่จะทดสอบ คูณด้วย 1,000 ครั้งในแอปพลิเคชันของคุณและฉันรับประกันได้ว่าในที่สุดนักพัฒนาจะยอมแพ้ในการทดสอบ ในทางกลับกันมันค่อนข้างง่ายที่จะปิดบังsayHelloฟังก์ชั่นด้วยสายลับและทดสอบว่ามันถูกเรียก

ตัวอย่างที่ใช้งานได้จริง - เพราะจริงๆแล้วใครใช้window.alert(...)ในรหัสการผลิตจริง ๆ - กำลังตรวจสอบนาฬิการะบบ ตัวอย่างเช่นนี่จะเป็นการตัดคำDateTime.Nowใน. NET time(...)ใน C / C ++ หรือSystem.currentTimeMillis()ใน Java คุณจริงๆต้องการที่จะตัดผู้ที่อยู่ในการพึ่งพาที่คุณสามารถฉีดเพราะพวกเขาไม่เพียง แต่เป็น (เกือบ) เป็นไปไม่ได้ที่จะเยาะเย้ย / ปลอมพวกเขาจะอ่านอย่างเดียวและไม่กำหนด การทดสอบใด ๆ ที่ครอบคลุมฟังก์ชั่นหรือวิธีการที่ทำให้การใช้งานฟังก์ชั่นนาฬิการะบบโดยตรงนั้นมีโอกาสสูงมากที่จะได้รับความล้มเหลวเป็นระยะ ๆ และ / หรือความล้มเหลวแบบสุ่ม

wrapper ที่แท้จริงคือฟังก์ชั่น 1 บรรทัดreturn DateTime.Now- แต่นั่นคือทั้งหมดที่คุณต้องการเพื่อนำวัตถุที่ออกแบบมาไม่ดีและไม่สามารถทดสอบได้มาทดสอบและทำให้มันเป็นวัตถุที่สะอาดและทดสอบได้ คุณสามารถแทนที่นาฬิกาปลอมสำหรับเสื้อคลุมและตั้งเวลาให้เป็นอะไรก็ได้ที่คุณต้องการ แก้ไขปัญหา.


2

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


2

ความคิดที่อยู่เบื้องหลังคำถามของคุณดูเหมือนจะเป็น: "ทำไมไม่เพียงแค่เขียนalert("Hello");โดยตรงมันค่อนข้างง่าย"

คำตอบคือส่วนหนึ่งเนื่องจากคุณไม่ต้องการโทรจริงๆalert("Hello")- คุณแค่อยากทักทาย

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

นี่คือสิ่งที่เข้าใจได้โดยคำศัพท์เช่นสิ่งที่เป็นนามธรรมทางอ้อม "การซ่อนรายละเอียดการใช้งาน" และแม้แต่ "รหัสที่แสดงออก"

การใช้เหตุผลเดียวกันกับการใช้ค่าคงที่แทนที่จะเขียนค่าดิบทุกที่ คุณสามารถเพียงแค่เขียน3.141592...ทุกครั้งที่คุณจำเป็นต้องเธ Math.PIแต่โชคดีที่มี

เราอาจมองalert()ตัวเอง ใครจะสนใจว่ามันสร้างและแสดงข้อความโต้ตอบนั้นหรือไม่ คุณแค่ต้องการเตือนผู้ใช้ ระหว่างที่คุณเขียนalert("Hello")และพิกเซลบนหน้าจอมีการเปลี่ยนแปลงรหัสและฮาร์ดแวร์ที่ลึกและลึกโดยแต่ละเลเยอร์จะบอกสิ่งที่ต้องการและเลเยอร์ถัดไปจะดูแลรายละเอียดจนกว่าเลเยอร์ที่ลึกที่สุดจะพลิกบางบิตใน หน่วยความจำวิดีโอ

คุณไม่ต้องการที่จะทำทุกอย่างด้วยตัวเองเพียงแค่กล่าวทักทาย

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

มันคือพีชคณิต


-1

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

ฟังก์ชั่นซึ่งคำนวณเฉพาะค่าตอบแทนการใช้เพียงข้อโต้แย้งก็ให้เรียกว่าบริสุทธิ์

A "ฟังก์ชั่น" ซึ่งดำเนินการกระทำที่เป็นจริงเป็นขั้นตอนซึ่งมีผลกระทบ

ผลกระทบใด ๆ ที่เกิดขึ้นระหว่างการคำนวณค่าเรียกว่าผลข้างเคียงและดีกว่าที่จะหลีกเลี่ยงพวกเขาหากเป็นไปได้ ("ฉันแค่ต้องการสตริงนั้นฉันไม่รู้ว่ามันจะตอกฐานข้อมูล!")

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

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

หากเราปฏิบัติตามกฎเหล่านี้เราอาจสิ้นสุดด้วยขั้นตอนเช่นsayHelloนี้ซึ่งไม่ต้องการข้อมูลใด ๆ และไม่มีผลลัพธ์ ดังนั้นอินเทอร์เฟซที่ดีที่สุดคือไม่มีอาร์กิวเมนต์และไม่ส่งคืนค่า นี่เป็นตัวอย่างที่ดีกว่าสำหรับการเรียก "console.log" ในระหว่างการคำนวณ

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

ในทำนองเดียวกันเพื่อลดความจำเป็นในการคำนวณในระหว่างขั้นตอนเราสามารถให้ขั้นตอนดำเนินการตามขั้นตอนอื่นเป็นพารามิเตอร์ (อาจเป็นผลลัพธ์ของฟังก์ชัน) เช่น. การทำโพรซีเดอร์และเรียกใช้ทีละรายการ


ดูเหมือนว่าคุณกำลังต่อต้าน OOP ที่นี่ซึ่งหลักการพื้นฐานคือ "บอกอย่าถาม" การปฏิบัติตามคำแนะนำที่นี่คือสิ่งที่ปกติจะนำไปสู่การเขียนโค้ดด้วยการเรียก "getFoo", "setFoo" และ "execute" ที่ไร้ประโยชน์ OOP เป็นเรื่องเกี่ยวกับการรวมข้อมูลและพฤติกรรมไม่ใช่การแยกพวกมันออก
Aaronaught

@Anaught มันเป็นความจริงที่ฉันไม่เห็นด้วยกับ OOP แต่ฉันก็ไม่แนะนำให้setFooโทรเพราะนั่นหมายถึงข้อมูลที่ไม่แน่นอน การเปลี่ยนแปลงเนื้อหาของตัวแปร / คุณสมบัติคือผลกระทบซึ่งทำให้การคำนวณทั้งหมดโดยใช้ข้อมูลนั้นไม่บริสุทธิ์ ฉันจะไม่แนะนำการexecuteโทรต่อ se แต่ฉันจะแนะนำrunFooขั้นตอนสำหรับการดำเนินการตามข้อโต้แย้งของพวกเขา
Warbo

-2

ฉันจะบอกว่ามันเป็นการรวมกันของคำตอบที่ได้รับจาก @MichaelT และ @Sleiman Jneidi

อาจมีหลายแห่งในรหัสที่คุณต้องการทักทายผู้ใช้ด้วยข้อความ Hello ดังนั้นคุณจึงบรรจุความคิดนั้นในวิธีการ ในวิธีการที่คุณสามารถแปลหรือขยายใน 'สวัสดี' ง่าย ๆ โดยการแสดงข้อความอีกต่อไป นอกจากนี้คุณอาจต้องการใช้กล่องโต้ตอบ JQuery ที่ดีแทนการแจ้งเตือน

ประเด็นก็คือการดำเนินการอยู่ในที่เดียว คุณเพียงแค่ต้องเปลี่ยนรหัสในที่เดียว (SayHello () อาจเป็นตัวอย่างที่ง่ายเกินไป)


@downvoter (s) - ระมัดระวังในการแบ่งปันความรู้ของคุณกับพวกเราที่เหลือ โพสต์ของฉันผิดเขียนไม่ดีหรืออะไร
พอล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.