การใช้ตัวแปร _ (ขีดล่าง) กับฟังก์ชันลูกศรใน ES6 / typescript


121

ฉันเจอโครงสร้างนี้ในตัวอย่างเชิงมุมและฉันสงสัยว่าทำไมถึงเลือกสิ่งนี้:

_ => console.log('Not using any parameters');

ฉันเข้าใจว่าตัวแปร _ หมายถึงไม่สนใจ / ไม่ใช้ แต่เนื่องจากเป็นตัวแปรเดียวจึงมีเหตุผลใดที่จะชอบใช้ _ มากกว่า:

() => console.log('Not using any parameters');

แน่นอนว่านี่ไม่สามารถพิมพ์ได้น้อยกว่าหนึ่งอักขระ ไวยากรณ์ () สื่อถึงเจตนาที่ดีกว่าในความคิดของฉันและยังมีความเฉพาะเจาะจงมากขึ้นด้วยเพราะอย่างอื่นฉันคิดว่าตัวอย่างแรกควรมีลักษณะดังนี้:

(_: any) => console.log('Not using any parameters');

ในกรณีที่มีความสำคัญนี่คือบริบทที่ใช้:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}


1
คุณจะกังวลเกี่ยวกับการพิมพ์หรือความเฉพาะเจาะจงสำหรับพารามิเตอร์ที่ไม่เคยใช้งานได้อย่างไร

3
ฉันเป็นนักพัฒนา C ++ โดยการค้าดังนั้นฉันคิดว่าฉันมักจะกังวลเกี่ยวกับความจำเพาะของประเภท :-)
หยุด

7
โดยส่วนตัวรูปแบบ _ => จะลดจำนวนวงเล็บทำให้อ่านง่ายขึ้น: doStuff () แล้ว (() => action ()) เทียบกับ doStuff () แล้ว (_ => action ())
Damien Golding

คำตอบ:


95

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

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

แม้ว่าฟังก์ชันลูกศรจะอนุญาตพารามิเตอร์เดียวโดยไม่มีวงเล็บ แต่ก็ไม่สอดคล้องกับศูนย์, ทำลายโครงสร้างเดี่ยว, ส่วนที่เหลือเดี่ยวและพารามิเตอร์หลายตัว:

let zeroParamFn = () => { ... };
let oneParamFn = param1 => { ... };
let oneParamDestructuredArrFn = ([param1]) => { ... };
let oneParamDestructuredObjFn = ({ param1 }) => { ... };
let twoParamsFn = (param1, param2) => { ... };
let restParamsFn = (...params) => { ... };

แม้ว่าis declared but never usedข้อผิดพลาดจะได้รับการแก้ไขใน TypeScript 2.0สำหรับพารามิเตอร์ที่ถูกขีดเส้นใต้ แต่_ยังสามารถเรียกunused variable/parameterคำเตือนจาก linter หรือ IDE ได้ นี่เป็นข้อโต้แย้งที่สำคัญสำหรับการทำเช่นนี้

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

let fn = (param1, _unusedParam2, param3) => { ... };

ด้วยเหตุผลที่ระบุไว้ข้างต้นโดยส่วนตัวแล้วฉันคิดว่า_ => { ... }รูปแบบรหัสเป็นโทนสีที่ไม่ดีที่ควรหลีกเลี่ยง


1
สั้นกว่าหนึ่งอักขระ แต่เป็นจำนวนการกดแป้นเดียวกันสำหรับ IDE ส่วนใหญ่เนื่องจากการกด(มักจะมาพร้อมกับไฟล์). ฉันชอบใช้pพารามิเตอร์เป็นการส่วนตัว ฉันยังสงสัยว่ามันมีปัญหาด้านประสิทธิภาพหรือไม่
Mojimi

69

()ไวยากรณ์บ่งบอกถึงความตั้งใจ IMHO ดีกว่าและยังเป็นประเภทที่เฉพาะเจาะจงมากขึ้น

ไม่ตรง ()กล่าวว่าฟังก์ชันไม่คาดหวังอาร์กิวเมนต์ใด ๆ แต่จะไม่ประกาศพารามิเตอร์ใด ๆ ฟังก์ชัน.lengthคือ 0

หากคุณใช้_มันจะระบุอย่างชัดเจนว่าฟังก์ชันจะถูกส่งผ่านหนึ่งอาร์กิวเมนต์ แต่คุณไม่สนใจมัน ฟังก์ชัน.lengthจะเป็น 1 ซึ่งอาจมีความสำคัญในบางกรอบ

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


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

ฉันเพิ่งรู้ว่ารหัสของฉันเต็มไปด้วย_ตัวแปรฟังก์ชันลูกศรที่ไม่ได้ใช้ฉันสงสัยว่ามีความแตกต่างด้านประสิทธิภาพหรือไม่เมื่อเทียบกับการใช้()
Mojimi

25

ฉันเดาว่า_ =>ถูกใช้มากกว่า() =>เพราะ_เป็นภาษาทั่วไปที่ไม่อนุญาตให้ละพารามิเตอร์เช่นใน JS

_ เป็นที่นิยมใน Go และยังใช้ใน Dart เพื่อระบุว่าพารามิเตอร์ถูกละเว้นและอาจเป็นสิ่งอื่นที่ฉันไม่รู้


4
ฉันคิดว่า Python เป็นไปตามแบบแผนนี้ด้วย
Jaime RGP

7
การใช้งาน_นี้น่าจะยืมมาจากภาษาที่ใช้งานได้เช่น ML และ Haskell ซึ่งมีมาก่อนการประดิษฐ์ Python มานานแล้ว (นับ แต่ Go, Dart หรือ TypeScript)
ruakh

1
Ruby ก็ทำเช่นนั้น ( po-ru.com/diary/rubys-magic-underscore ) และ F # ด้วย (และภาษาอื่น ๆ ที่ได้รับอิทธิพลจากตระกูล ML)
Mariusz Pawelski

Scala ชอบขีดล่าง ( includehelp.com/scala/use-of-underscore-in-scala.aspx ) มีภาษาใดบ้างที่ใช้หลังจากสิ่งที่ Scala กำลังทำกับประเภทที่ไม่ระบุตัวตนพร้อมขีดล่าง
แซม

ฉันเดาว่า Scala เอามาจากภาษาอื่นด้วย แทบจะไม่มีอะไรในภาษาโปรแกรมที่ไม่มีอยู่แล้วในยุค 70: D ส่วนใหญ่เป็นเพียงวิธีใหม่ในการรวมสิ่งต่างๆเข้าด้วยกัน
GünterZöchbauer

11

เป็นไปได้ที่จะแยกความแตกต่างระหว่างสองประเพณีและกรอบงานบางอย่างใช้สิ่งนี้เพื่อแสดงการเรียกกลับประเภทต่างๆ ตัวอย่างเช่นฉันคิดว่า nodes express framework ใช้สิ่งนี้เพื่อแยกความแตกต่างระหว่างประเภทของมิดเดิลแวร์เช่นตัวจัดการข้อผิดพลาดใช้อาร์กิวเมนต์สามตัวในขณะที่การกำหนดเส้นทางใช้สอง

ความแตกต่างดังกล่าวอาจมีลักษณะดังตัวอย่างด้านล่าง:

const f1 = () => { } // A function taking no arguments
const f2 = _ => { }  // A function with one argument that doesn't use it

function h(ff) { 
  if (ff.length === 0) {
    console.log("No argument function - calling directly");
    ff();
  } else if (ff.length === 1) {
    console.log("Single argument function - calling with 1");
    ff(1);
  }
}

h(f1);
h(f2);


1
นี่เป็นไปตามคำตอบของ Bergi แต่ฉันคิดว่าการเพิ่มตัวอย่างเป็นการแก้ไขมากกว่าที่ฉันยินดีที่จะทำกับคนอื่นโพสต์
Michael Anderson

0

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


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

ตัวอย่าง:

// simple number doubling function
f = _=> {
    _ = _ * 2;
    return _;
}

console.log(f(2)); // returns 4
console.log(f(10)); // returns 20

ทดสอบกับคอนโซล Chrome เวอร์ชัน 76.0.3809.132 (รุ่นอย่างเป็นทางการ) (64 บิต)


1
ขีดล่าง '_' เป็นชื่อตัวแปรทางกฎหมายและไม่ใช่รูปแบบภาษาพิเศษมีเพียงความหมายพิเศษตามแบบแผนเท่านั้น คำเตือน Linter เกี่ยวกับพารามิเตอร์ที่ไม่ได้ใช้สามารถปิดเสียงได้โดยใช้คำนำหน้าขีดล่าง ฉันเดาว่า _ ด้วยตัวมันเองเป็นเพียงวิธีที่สั้นที่สุดในการบอกว่าไม่ได้ใช้
หยุด

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