Tại sao việc truyền các hàm ẩn danh lớn làm đối số cho các hàm khác được chấp nhận rộng rãi trong JavaScript?


27

Tôi có một ý kiến (mà tôi chắc chắn sẽ được chia sẻ bởi một số người) rằng việc chuyển các hàm ẩn danh chứa nhiều dòng mã, vì các đối số cho các hàm khác ảnh hưởng đến khả năng đọc và tự viết tài liệu một cách quyết liệt, đến mức tôi cảm thấy nó sẽ tốt hơn nhiều cho bất cứ ai có khả năng sử dụng mã để chỉ khai báo một hàm được đặt tên. Hoặc ít nhất gán hàm ẩn danh đó cho một biến trước khi khai báo hàm chính

Tuy nhiên, nhiều thư viện JavaScript (jQuery, d3.js / NVD3.js) chỉ để đưa ra một vài ví dụ, sử dụng các hàm lớn theo cách này.

Tại sao điều này được chấp nhận rộng rãi trong JavaScript? Đây có phải là một điều văn hóa, hoặc có những lợi thế mà tôi đang thiếu, điều này sẽ khiến việc sử dụng được ưu tiên hơn so với việc khai báo một hàm được đặt tên?


1
Nó có thể có rất nhiều để làm với việc sử dụng đóng cửa . Nó cũng có thể phải làm với việc không muốn phơi bày chức năng thực tế ra thế giới bên ngoài (đó là lý do tại sao nó ẩn danh).
Robert Harvey

3
@RobertHarvey Nói cách khác, đó là một cách giải quyết cho JavaScript không có công khairiêng tư ?
Mason Wheeler

2
Ở nhiều nơi, một hàm ẩn danh lớn đọc giống như một khối và thường cảm thấy khá tốt khi bạn đã quen với nó. Quy tắc phạm vi thậm chí hỗ trợ cảm giác khối.

5
@MasonWheeler: Điều đó phụ thuộc vào quan điểm của bạn. Một lập trình viên Scheme hoặc ECMAScript có thể nói điều đó publicprivatelà cách giải quyết cho việc không có các bao đóng thích hợp.
Jörg W Mittag

1
@ JörgWMittag Hoan hô cho Vợt, nhà tài trợ ngôn ngữ chính thức của XKCD 927!
Mason Wheeler

Câu trả lời:


23

Ba lý do chính tôi có thể nghĩ đến:

  1. Truy cập phạm vi phụ huynh
  2. Riêng tư
  3. Giảm tên được xác định trong phạm vi cao hơn

Quyền truy cập phạm vi cha mẹ: Định nghĩa hàm nội tuyến cho phép mã nội tuyến có quyền truy cập vào các biến được xác định trong phạm vi cha. Điều này có thể rất hữu ích cho nhiều thứ và có thể làm giảm số lượng hoặc độ phức tạp của mã nếu được thực hiện đúng cách.

Nếu bạn đặt mã trong một hàm được xác định bên ngoài phạm vi này và sau đó gọi mã, thì bạn sẽ phải chuyển bất kỳ trạng thái cha mẹ nào mà nó muốn truy cập vào hàm.

Quyền riêng tư: Mã bên trong một định nghĩa ẩn danh nội tuyến là riêng tư hơn và không thể được gọi bằng mã khác.

Giảm tên được xác định trong phạm vi cao hơn: Điều này quan trọng nhất khi hoạt động trong phạm vi toàn cầu, nhưng một tuyên bố ẩn danh nội tuyến giúp không phải xác định một biểu tượng mới trong phạm vi hiện tại. Vì Javascript vốn không yêu cầu sử dụng không gian tên, nên tránh việc xác định bất kỳ ký hiệu toàn cầu nào nhiều hơn yêu cầu tối thiểu.


Biên tập: Nó dường như đã trở thành một thứ văn hóa trong Javascript khi khai báo một thứ ẩn danh nội tuyến nào đó được coi là "tốt hơn" so với việc xác định hàm và gọi nó ngay cả khi không sử dụng quyền truy cập phạm vi cha. Tôi nghi ngờ điều này ban đầu là do vấn đề ô nhiễm không gian tên toàn cầu trong Javascript, sau đó có lẽ là do vấn đề riêng tư. Nhưng bây giờ nó đã biến thành một phần của một thứ văn hóa và bạn có thể thấy nó được thể hiện trong rất nhiều bộ luật công khai (giống như những gì bạn đề cập).

Trong các ngôn ngữ như C ++, hầu hết có lẽ sẽ coi đó là một cách thực hành không lý tưởng để có một chức năng khổng lồ trải dài trên nhiều trang / màn hình. Tất nhiên, C ++ có không gian tên được tích hợp sẵn, không cung cấp quyền truy cập phạm vi cha mẹ và có các tính năng bảo mật để nó có thể được thúc đẩy hoàn toàn bởi khả năng đọc / bảo trì trong khi Javascript phải sử dụng biểu thức mã để đạt được quyền riêng tư và quyền truy cập phạm vi cha mẹ. Vì vậy, JS dường như đã được thúc đẩy theo một hướng khác và nó trở thành một thứ văn hóa trong ngôn ngữ, ngay cả khi những thứ thúc đẩy hướng đó không cần thiết trong một trường hợp cụ thể.


Vì một nhà phát triển C ++ gần đây đã chuyển sang JS cho rất nhiều công việc của tôi, câu trả lời này rất có ý nghĩa, đặc biệt là điểm 'truy cập phạm vi cha mẹ' - nó thực sự có khả năng đơn giản hóa rất nhiều mã của bạn. Một nitpick - C ++ không cung cấp quyền truy cập phạm vi cha mẹ trong C ++ 11 lambdas :) Mặc dù chắc chắn +1.
Chỉ huy Coriander Salamander

8

Các hàm ẩn danh được sử dụng cho nhiều mục đích hơn trong JavaScript so với hầu hết các ngôn ngữ.

Đầu tiên, chúng được sử dụng cho không gian tên và phạm vi khối. Cho đến gần đây, JavaScript đã thiếu các mô-đun hoặc bất kỳ loại cơ chế không gian tên nào khác dẫn đến việc sử dụng các hàm ẩn danh để cung cấp chức năng đó thông qua Mô hình Mô-đun. Sẽ hoàn toàn không có lợi ích trong việc đặt tên cho các chức năng này. Ở quy mô nhỏ hơn, do thiếu JavaScript phạm vi khối cho đến gần đây, một mô hình tương tự đã được sử dụng để bắt chước phạm vi khối; Đáng chú ý nhất là trong cơ thể của các vòng. Sử dụng một chức năng được đặt tên trong trường hợp này sẽ được tích cực che giấu.

Thứ hai, và ít cụ thể hơn JavaScript, các hàm ẩn danh thường được sử dụng với các hàm bậc cao hơn bắt chước các cấu trúc điều khiển. Ví dụ: eachphương pháp của jQuery . Tôi nghi ngờ bạn trừu tượng mọi thân vòng lặp hoặc nhánh nhánh thành một hàm bất cứ khi nào nó dài hơn một vài dòng. Logic tương tự áp dụng trong trường hợp này.

Một lý do cuối cùng là lập trình dựa trên sự kiện là phổ biến trong JavaScript, điều này có xu hướng dẫn đến mã kiểu tiếp tục vô tình tiếp tục . Bạn thực hiện cuộc gọi AJAX và đăng ký một cuộc gọi lại, khi được thực hiện, sẽ thực hiện một cuộc gọi AJAX khác và đăng ký một cuộc gọi lại, v.v ... Nếu các cuộc gọi là đồng bộ thay vì không đồng bộ, đây sẽ chỉ là một chuỗi mã thẳng trong một phạm vi từ vựng duy nhất . Một lần nữa, tôi nghi ngờ bạn sẽ trừu tượng hóa mỗi vài dòng mã đường thẳng thành một hàm.

Ngoài ra còn có các yếu tố văn hóa và, vì những lý do trên, các hàm ẩn danh phổ biến hơn nhiều trong JavaScript so với nhiều ngôn ngữ khác và được sử dụng thoải mái / lỏng lẻo hơn nhiều ngôn ngữ khác.


Các cấu trúc có lẽ ngây thơ của riêng tôi trong mã hóa C ++ đôi khi đã áp dụng các nguyên tắc mã hóa dựa trên sự kiện và các cuộc gọi lại từ JavaScript thông qua std :: function và lambdas. Trong trường hợp của tôi, đó là một phần vì tôi đang thực hiện mã UI trong C ++ và không muốn thực hiện các hoạt động chặn. Tôi tò mò liệu các thực tiễn của JavaScript chỉ đơn giản là hữu ích cho bất kỳ ai miễn là ngôn ngữ hỗ trợ tốt cho họ.
Katana314
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.