Sử dụng biến _ (gạch dưới) với các hàm mũi tên trong ES6 / Typecript


119

Tôi đã bắt gặp cấu trúc này trong một ví dụ Angular và tôi tự hỏi tại sao nó được chọn:

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

Tôi hiểu rằng biến _ có nghĩa là không quan tâm / không được sử dụng nhưng vì đó là biến duy nhất nên có bất kỳ lý do nào để sử dụng _ over:

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

Chắc chắn đây không phải là về một ký tự ít hơn để gõ. Cú pháp () truyền đạt ý định tốt hơn theo ý kiến ​​của tôi và cũng là loại cụ thể hơn vì nếu không, tôi nghĩ rằng ví dụ đầu tiên nên trông như thế này:

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

Trong trường hợp nó quan trọng, đây là bối cảnh mà nó được sử dụng:

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


1
Làm thế nào bạn có thể lo lắng về việc gõ hoặc gõ tính đặc hiệu cho một tham số không bao giờ được sử dụng?

3
Tôi là một nhà phát triển C ++ bằng thương mại nên tôi đoán tôi luôn lo lắng về tính đặc hiệu của loại :-).
Dừng

6
Cá nhân, mẫu _ => làm giảm số lượng dấu ngoặc giúp dễ đọc hơn: doStuff (). Then (() => action ()) so với doStuff (). Then (_ => action ()).
Damien Golding

Câu trả lời:


92

Lý do tại sao phong cách này có thể được sử dụng (và có thể tại sao nó được sử dụng ở đây) _là một ký tự ngắn hơn ().

Các dấu ngoặc đơn tùy chọn rơi vào cùng một vấn đề kiểu như dấu ngoặc nhọn tùy chọn . Đây là một vấn đề về hương vị và phong cách mã cho hầu hết các phần, nhưng tính dài dòng được ưa chuộng ở đây vì tính nhất quán.

Mặc dù các hàm mũi tên cho phép một tham số duy nhất không có dấu ngoặc đơn, nhưng nó không nhất quán với số 0, đơn bị phá hủy, phần còn lại đơn và nhiều tham số:

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

Mặc dù is declared but never usedlỗi đã được sửa trong TypeScript 2.0 đối với các tham số chưa được xác nhận, nhưng _cũng có thể kích hoạt unused variable/parametercảnh báo từ kẻ nói dối hoặc IDE. Đây là một lập luận đáng kể chống lại việc này.

_có thể được sử dụng thông thường cho các tham số bỏ qua (như câu trả lời khác đã được giải thích). Mặc dù điều này có thể được coi là chấp nhận được, nhưng thói quen này có thể dẫn đến xung đột với _không gian tên Underscore / Lodash, cũng có vẻ khó hiểu khi có nhiều tham số bị bỏ qua. Vì lý do này, có lợi khi đặt tên đúng cho các tham số được gạch dưới (được hỗ trợ trong TS 2.0), cũng tiết kiệm thời gian để tìm ra chữ ký hàm và tại sao các tham số được đánh dấu là bỏ qua (điều này bất chấp mục đích của _tham số là phím tắt):

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

Vì những lý do được liệt kê ở trên, cá nhân tôi sẽ coi _ => { ... }phong cách mã là một giai điệu xấu nên tránh.


1
Nó ngắn hơn một ký tự nhưng nó có cùng số lượng phím nhấn cho hầu hết các IDE, vì nhấn (thường đi kèm với a ). Cá nhân tôi thích sử dụng pcho tham số, tôi cũng tự hỏi liệu nó có vấn đề gì về hiệu năng không
Mojimi

67

Các ()cú pháp truyền đạt IMHO tốt hơn ý định và cũng nhiều loại hình cụ thể

Không chính xác. ()nói rằng hàm không mong đợi bất kỳ đối số nào, nó không khai báo bất kỳ tham số nào. Hàm số .lengthlà 0.

Nếu bạn sử dụng _, nó nói rõ rằng hàm sẽ được thông qua một đối số, nhưng bạn không quan tâm đến nó. Hàm .lengthsẽ là 1, có thể quan trọng trong một số khung.

Vì vậy, từ góc độ loại, có thể chính xác hơn để làm (đặc biệt là khi bạn không gõ nó với anynhưng, giả sử, _: Event). Và như bạn đã nói, đó là một ký tự ít hơn để gõ cũng dễ dàng tiếp cận hơn trên một số bàn phím.


6
Suy nghĩ đầu tiên của tôi là _ làm cho nó chỉ rõ ràng theo quy ước rằng không có đối số để xem xét khi cố gắng hiểu chức năng. Việc sử dụng () làm cho nó rõ ràng, không cần quét mã để sử dụng _ (có thể vi phạm quy ước). Nhưng bạn cũng mở mắt ra để xem xét giá trị của tài liệu rằng có một giá trị được truyền cho hàm, điều này sẽ không luôn luôn rõ ràng.
Dừng

Tôi mới nhận ra mã của mình có đầy đủ các _biến hàm mũi tên không được sử dụng , tôi tự hỏi liệu có sự khác biệt nào về hiệu năng so với việc sử dụng không()
Mojimi

24

Tôi đoán _ =>là chỉ được sử dụng () =>_phổ biến trong các ngôn ngữ khác, nơi nó không được phép bỏ qua các tham số như trong JS.

_ là phổ biến trong Go và nó cũng được sử dụng trong Dart để chỉ ra một tham số bị bỏ qua và có lẽ những thông số khác tôi không biết.


4
Python cũng tuân theo quy ước này, tôi nghĩ vậy.
Jaime RGP

7
Việc sử dụng _này có lẽ được mượn từ các ngôn ngữ chức năng như ML và Haskell, nơi mà từ lâu nó đã phát minh ra Python (chứ đừng nói là Go, Dart hoặc TypeScript).
ruakh

1
Ruby cũng vậy ( po-ru.com/diary/rubys-magic-underscore ) và F # nữa (và các ngôn ngữ khác chịu ảnh hưởng của gia đình ML)
Mariusz Pawelski

Scala thích gạch dưới ( incehelp.com/scala/use-of-underscore-in-scala.aspx ). Những ngôn ngữ nào được sử dụng sau những gì Scala đang làm với các loại ẩn danh với dấu gạch dưới.
Sam

Tôi đoán Scala cũng lấy nó từ một số ngôn ngữ khác. Hầu như không có bất cứ điều gì trong các ngôn ngữ lập trình đã không tồn tại trong những năm 70: D Chủ yếu chỉ là những cách mới để kết hợp các thứ.
Günter Zöchbauer

11

Có thể phân biệt giữa hai cách sử dụng và một số khung sử dụng điều này để thể hiện các loại gọi lại khác nhau. Ví dụ, tôi nghĩ rằng các nút express express sử dụng điều này để phân biệt giữa các loại phần mềm trung gian, ví dụ trình xử lý lỗi sử dụng ba đối số, trong khi định tuyến sử dụng hai đối số.

Sự khác biệt như vậy có thể trông giống như ví dụ dưới đây:

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
Điều này dựa trên câu trả lời của Bergi, nhưng tôi nghĩ việc thêm một ví dụ là chỉnh sửa nhiều hơn một chút so với việc tôi vui lòng làm bài đăng của ai đó.
Michael Anderson

0

Khi tôi viết bài đăng, tôi có ấn tượng _là cách duy nhất để tạo các hàm mũi tên mà không có (), điều đó khiến tôi tin rằng việc sử dụng _có thể có một số lợi thế nhỏ, nhưng tôi đã sai. @Halt đã xác nhận trong các ý kiến ​​rằng nó hoạt động giống như các biến khác, nó không phải là một cấu trúc ngôn ngữ đặc biệt.


Tôi muốn đề cập đến một điều nữa tôi nhận ra về các chức năng mũi tên gạch dưới này trong khi tự kiểm tra tôi không tìm thấy đề cập ở bất cứ đâu. Bạn có thể sử dụng dấu gạch dưới trong hàm làm tham số , mặc dù điều này có thể không nhằm mục đích sử dụng vì nó được cho là đại diện cho một tham số không sử dụng. Để rõ ràng, tôi sẽ không thực sự khuyên bạn nên sử dụng nó theo cách này. nhưng nó có thể hữu ích để biết đối với những thứ như codegolf , những thách thức khi bạn viết mã ngắn nhất (hóa ra bạn chỉ có thể sử dụng bất kỳ ký tự nào mà không có ()). Tôi có thể tưởng tượng một số trường hợp sử dụng thực tế trong đó các thư viện sử dụng điều này và bạn cần sử dụng nó ngay cả khi họ không có ý định cho chức năng đó.

Thí dụ:

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

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

Đã thử nghiệm với bảng điều khiển Chrome, Phiên bản 76.0.3809.132 (Bản dựng chính thức) (64-bit)


1
Dấu gạch dưới '_' là tên biến hợp pháp và không phải là cấu trúc ngôn ngữ đặc biệt, chỉ được quy định theo ý nghĩa đặc biệt. Cảnh báo của Linter về các tham số không sử dụng có thể được tắt tiếng bằng cách sử dụng tiền tố gạch dưới. Tôi đoán _ tự nó chỉ là cách ngắn nhất để nói không sử dụng.
Dừng

@ Xin cảm ơn đã làm rõ, tốt để biết chắc chắn. Tôi thực sự không nhận ra bạn có thể thực hiện các chức năng mũi tên mà không cần ()trước khi tôi đăng bài này, tôi nghĩ đó _là cách duy nhất, đó là lý do tại sao tôi quyết định chỉ ra điều này. Với suy nghĩ này, hóa ra nó không có gì đặc biệt để sử dụng ngay cả khi chơi golf, vì bạn chỉ có thể sử dụng một nhân vật thông thường. Tốt hơn được sử dụng đơn giản cho các quy ước sau, như bạn đã nói.
Matsyir
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.