Quy ước JavaScript cho không hoạt động là gì?


121

Quy ước JavaScript cho không hoạt động là gì? Giống như một passlệnh Python .

  • Một tùy chọn đơn giản là một hàm trống: function() {}
  • jQuery cung cấp $.noop(), chỉ đơn giản gọi hàm trống ở trên.
  • Có thể chấp nhận chỉ đơn giản là nhập một giá trị falsehoặc 0?

Trong ngữ cảnh ... tất cả những thứ này đều hoạt động mà không gây ra lỗi trong Chrome:

var a = 2;
(a === 1) ? alert(1) : function() {};
(a === 1) ? alert(1) : $.noop();
(a === 1) ? alert(1) : false;
(a === 1) ? alert(1) : 0;

EDIT: Rất nhiều người đã trả lời, "đừng làm điều này! Thay đổi cấu trúc mã!" Điều này làm tôi nhớ đến một bài đăng mà ai đó hỏi làm thế nào để đánh hơi trình duyệt. Anh ta đã nhận được một loạt các bài đăng với nội dung: "ĐỪNG LÀM RỒI! NÓ CỨ SAU", nhưng không ai nói cho anh ta cách đánh hơi trình duyệt . Đây không phải là một đánh giá mã. Hãy tưởng tượng rằng bạn đang xử lý mã kế thừa không thể thay đổi và nếu không có một số chức năng được truyền vào, nó sẽ gây ra lỗi. Hoặc, đơn giản, đó là cách khách hàng muốn và họ trả tiền cho tôi . Vì vậy, trân trọng, vui lòng trả lời câu hỏi : Cách tốt nhất để chỉ định chức năng "không hoạt động" trong JavaScript là gì?

EDIT2: Làm thế nào về một trong số này?

true;
false;
0;
1;
null;

7
Tại sao không phải là một câu lệnh if đơn giản?
eprebello

11
Không có lựa chọn thay thế 0nào có hiệu quả tốt hơn (hoặc tệ hơn). Tôi muốn nói điều đúng đắn là if (a === 1) doSomething();và không sử dụng ? :khi nó không có ý nghĩa.
Pointy

6
Bạn đang lạm dụng toán tử ternary với một tác dụng phụ. Nếu bạn phải, làmif (statement) action; else ;
mplungjan

falsehoặc 0sẽ làm việc; nulllà một cách tốt đẹp để thể hiện no-op.
Matt

3
Tôi hy vọng
chim nhạn

Câu trả lời:


95

Để trả lời câu hỏi ban đầu, cách triển khai gọn gàng nhất của hàm noop trong Javascript thuần túy (cũng được thảo luận ở đây ) là Function.prototype . Điều này là do:

  1. Function.prototype là một hàm:

typeof Function.prototype === "function" // returns true

  1. Nó có thể được gọi như là một hàm và về cơ bản không có gì như được hiển thị ở đây:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Mặc dù đây là "noop đúng" vì hầu hết các trình duyệt dường như không làm gì để thực thi noop được xác định theo cách này (và do đó tiết kiệm chu kỳ CPU), có thể có một số vấn đề về hiệu suất liên quan đến điều này (cũng được đề cập bởi những người khác trong các bình luận hoặc trong câu trả lời khác).

Tuy nhiên, điều đó đang được nói, bạn có thể dễ dàng xác định hàm noop của riêng mình và, nguyên vẹn, nhiều thư viện và khung cũng cung cấp các hàm noop. Dưới đây là một số ví dụ:

var noop = function () {};           // Define your own noop in ES3 or ES5
const noop = () => {};               // Define in ES6 as Lambda (arrow function)
setTimeout(noop, 10000);             // Using the predefined noop

setTimeout(function () {} , 10000);  // Using directly in ES3 or ES5
setTimeout(() => {} , 10000);        // Using directly in ES6 as Lambda (arrow function)

setTimeout(angular.noop, 10000);     // Using with AngularJS 1.x
setTimeout(jQuery.noop, 10000);      // Using with jQuery

Dưới đây là danh sách theo thứ tự chữ cái của các triển khai khác nhau của các hàm noop (hoặc các cuộc thảo luận liên quan hoặc tìm kiếm google):

AngularJS 1.x , Angular 2+ (Dường như không có triển khai riêng - sử dụng của riêng bạn như được hiển thị ở trên), Ember , jQuery , Lodash , NodeJS , Ramda , React (Dường như không có triển khai riêng - hãy sử dụng riêng của bạn như hình trên), RxJS , gạch dưới

LINE LINE : Mặc dù Function.prototype là một cách thanh lịch để thể hiện một noop trong Javascript, tuy nhiên, có thể có một số vấn đề về hiệu suất liên quan đến việc sử dụng nó. Vì vậy, bạn có thể xác định và sử dụng của riêng bạn (như được hiển thị ở trên) hoặc sử dụng một định nghĩa của thư viện / khung mà bạn có thể đang sử dụng trong mã của mình.


5
Đây nên là câu trả lời. Một thậm chí có thể sử dụng Function.prototype()nếu bạn không cần thời gian chờ và muốn nó thực thi ngay lập tức.
tải

1
setTimeout(Function(), 10000);
iegik

@iegik: +1. Ư, bạn đung. Tất cả những điều sau đây là tương đương: setTimeout (function () {}, 10000); HOẶC setTimeout (Hàm mới (), 10000); HOẶC setTimeout (Hàm (), 10000); HOẶC setTimeout (Chức năng, 10000); vì ngữ pháp Javascript và triển khai Hàm xây dựng hàm cho phép các cấu trúc này.
Alan CS

5
Trong ES6 hoặc sử dụng babel hoặc một bộ chuyển mã khác (( )=>{};)về mặt kỹ thuật Pure JS và ngắn hơn nhiều function () {}nhưng tương đương chính xác.
Ray Foss

2
Tôi đã quan tâm đến việc tìm kiếm một cấu trúc không giống như để tắt mã gỡ lỗi trong chương trình của mình một cách hiệu quả. Trong C / C ++, tôi đã sử dụng macro. Tôi đã thử nghiệm gán fn của mình cho Function.prototype và định thời gian cho nó, so sánh các kết quả với việc chỉ có một câu lệnh if bên trong hàm để trả về ngay lập tức. Tôi cũng so sánh các kết quả này với việc loại bỏ hoàn toàn chức năng khỏi vòng lặp. Thật không may, Function.prototype hoàn toàn không hoạt động tốt. việc gọi một hàm rỗng có hiệu năng vượt trội hơn nhiều, thậm chí còn nhanh hơn gọi hàm với phép thử 'nếu' đơn giản bên trong để trả về.
bearvarine

72

Noop ngắn gọn và hiệu quả nhất là một hàm mũi tên trống : ()=>{}.

Các hàm mũi tên hoạt động tự nhiên trong tất cả các trình duyệt trừ IE (có một biến đổi babel nếu bạn phải): MDN


()=>{} so với Function.Prototype

  • ()=>{}87% nhanh hơn Function.prototypetrong Chrome 67.
  • ()=>{}25% nhanh hơn Function.prototypetrong Firefox 60.
  • ()=>{}85% nhanh hơn so với Function.prototypeEdge (2018/06/15) .
  • ()=>{}mã ít hơn 65% so với Function.prototype.

Bài kiểm tra dưới đây nóng lên bằng cách sử dụng chức năng mũi tên để phân biệt Function.prototype, nhưng chức năng mũi tên là người chiến thắng rõ ràng:

const noop = ()=>{};
const noopProto = Function.prototype;

function test (_noop, iterations) {
    const before = performance.now();
    for(let i = 0; i < iterations; i++) _noop();
    const after = performance.now();
    const elapsed = after - before;
    console.info(`${elapsed.toFixed(4)}MS\t${_noop.toString().replace('\n', '')}\tISNOOP? ${_noop() === undefined}`);
    return elapsed;
}

const iterations = 10000000
console.info(`noop time for ${iterations.toLocaleString()} iterations`)
const timings = {
    noop: test(noop, iterations),
    noopProto: test(noopProto, iterations)
}

const percentFaster = ((timings.noopProto - timings.noop)/timings.noopProto).toLocaleString("en-us", { style: "percent" });
console.info(`()=>{} is ${percentFaster} faster than Function.prototype in the current browser!`)


1
Tôi đã tạo một bài kiểm tra jsPerf để so sánh một số tùy chọn: noop-function . Có vẻ như trong Firefox 54, tất cả các lựa chọn thay thế dường như tương đương nhau; trong Chromium 58, Function.prototypechậm hơn rất nhiều, nhưng không có tùy chọn nào khác có lợi thế rõ ràng.
Lucas Werkmeister

_=>{}là một nhân vật ít hơn và làm điều tương tự.
Ross Attrill

@RossAttrill * điều tương tự - _=>{}có một tham số duy nhất. Nếu ai đó đang sử dụng TypeScript với cấu hình khá nghiêm ngặt, điều đó sẽ không được biên dịch. Nếu bạn gọi nó, IDE của bạn có thể sẽ cho bạn biết nó chấp nhận một tham số duy nhất có thể thuộc bất kỳ loại nào (cả JavaScript và đặc biệt là TypeScript trong vscode).
cchamberlain

15

bất cứ điều gì bạn có xu hướng đạt được ở đây là sai. Biểu thức ternary sẽ không được sử dụng như một tuyên bố đầy đủ, chỉ trong biểu thức, vì vậy câu trả lời cho câu hỏi của bạn là:

không có đề xuất nào của bạn, thay vào đó hãy làm:

var a = 2;
if (a === 1)
    alert(1)
// else do nothing!

sau đó mã dễ hiểu, dễ đọc và hiệu quả nhất có thể.

Tại sao làm cho nó khó khăn hơn, khi nó có thể đơn giản?

biên tập:

Vì vậy, về cơ bản, lệnh "không hoạt động" có chỉ ra cấu trúc mã kém hơn không?

Bạn đang thiếu quan điểm của tôi. Tất cả những điều trên là về biểu hiện của chim nhạn x ? y : z.

Nhưng, một lệnh không hoạt động không có nghĩa trong các ngôn ngữ cấp cao hơn như Javascript.

Nó thường được sử dụng, trong các ngôn ngữ cấp thấp hơn như assembly hoặc C, như một cách để làm cho bộ xử lý không làm gì cho một lệnh cho mục đích thời gian.

Trong JS, cho dù bạn làm 0;, null;, function () {};hoặc một tuyên bố trống rỗng, có những cơ hội tuyệt vời mà nó sẽ bị bỏ qua bởi các thông dịch khi nó được đọc nó, nhưng trước khi nó được giải thích, vì vậy cuối cùng, bạn sẽ chỉ làm cho chương trình của bạn được tải chậm hơn bởi một lượng thời gian rất nhỏ Nota Bene : Tôi giả định điều này, vì tôi không tham gia vào bất kỳ trình thông dịch JS được sử dụng rộng rãi nào và có nhiều khả năng mỗi trình thông dịch có chiến lược riêng.

Trong trường hợp bạn sử dụng một cái gì đó phức tạp hơn một chút, như $.noop()hoặc var foo = function () {}; foo(), thì trình thông dịch có thể thực hiện một cuộc gọi hàm không đáng tin mà cuối cùng sẽ làm hỏng một vài byte của ngăn xếp hàm của bạn và một vài chu kỳ.

Lý do duy nhất tôi thấy một chức năng như $.noop()sẽ tồn tại, là vẫn có thể cung cấp chức năng gọi lại cho một số chức năng sự kiện sẽ đưa ra một ngoại lệ nếu nó không thể gọi lại cuộc gọi đó. Nhưng sau đó, nó nhất thiết phải là một chức năng bạn cần cung cấp và noopđặt tên cho nó là một ý tưởng hay vì vậy bạn đang nói với độc giả của mình (và đó có thể là bạn trong 6 tháng) rằng bạn cố tình cung cấp một chức năng trống.

Cuối cùng, không có thứ gọi là cấu trúc mã "kém hơn" hay "vượt trội". Bạn có thể đúng hoặc sai trong cách bạn sử dụng các công cụ của mình .. Sử dụng một ternary cho ví dụ của bạn giống như sử dụng búa khi bạn muốn vặn vít. Nó sẽ hoạt động, nhưng bạn không chắc bạn có thể treo thứ gì đó trên cái ốc vít đó.

Điều có thể được coi là "thấp kém" hoặc "vượt trội" là thuật toán và ý tưởng bạn đưa vào mã của mình. Nhưng đó là một điều khác.


1
Vì vậy, về cơ bản, lệnh "không hoạt động" có chỉ ra cấu trúc mã kém hơn không?
kmiklas

3
@kmiklas: Tôi không thể nói rằng tôi đã từng tìm thấy một nhu cầu chính đáng cho một NOOP, bên ngoài trình biên dịch chương trình.
Matt Burland

@zmo: Tôi hiểu quan điểm của bạn về cách nhận xét của bạn liên quan đến biểu thức ternary; mọi người dường như đã bỏ lỡ quan điểm của tôi rằng đây chỉ là một ví dụ minh họa cho lời kêu gọi chức năng "Không hoạt động".
kmiklas

1
Tất nhiên có những lý do để muốn / cần một tính năng không hoạt động. Đừng tạo ra sự khái quát rộng rãi dựa trên 12 giây suy nghĩ sâu sắc của bạn về điều gì đó. JavaScript là một ngôn ngữ làm cho các chức năng có thể kiểm soát hoàn toàn dưới dạng các biến. Giả sử bạn có nhu cầu vô hiệu hóa một chức năng mà không cần kiểm tra rõ ràng? Điều này sẽ là hoàn hảo cho điều đó. Nếu bạn có một hàm xuất hiện thường xuyên, chẳng hạn như câu lệnh gỡ lỗi, sẽ rất tốt để có thể tắt nó bằng cách gán lại hàm cho no-op thay vì phải thêm mã bổ sung để kiểm tra một số biến mỗi khi hàm xuất hiện .
bearvarine

2
@bearvarine cảm ơn bạn vì ý kiến ​​cao mà bạn đang có của tôi :-D. Bạn hoàn toàn đúng trong nhận xét của mình, nhưng nó không thực sự dành cho thiết kế mã, chỉ là thiết kế mô phỏng bằng cách sử dụng hack. Những gì bạn mô tả cũng được gọi là vá khỉ, và có một lý do cho điều đó ;-)
zmo

7

Tôi nghĩ rằng jQuery noop()chủ yếu nhằm ngăn chặn mã bị sập bằng cách cung cấp một hàm mặc định khi không có sẵn yêu cầu. Ví dụ: xem xét mẫu mã sau đây, $.noopđược chọn nếu fakeFunctionkhông được xác định, ngăn cuộc gọi tiếp theo fnkhông bị sập:

var fn = fakeFunction || $.noop;
fn() // no crash

Sau đó, noop()cho phép lưu bộ nhớ bằng cách tránh ghi cùng một hàm trống nhiều lần ở mọi nơi trong mã của bạn. Nhân tiện, $.noopngắn hơn một chút function(){}(6 byte được lưu trên mỗi mã thông báo). Vì vậy, không có mối quan hệ giữa mã của bạn và mẫu hàm trống. Sử dụng null, falsehoặc 0nếu bạn thích, trong trường hợp của bạn sẽ không có tác dụng phụ. Hơn nữa, đáng chú ý là mã này ...

true/false ? alert('boo') : function(){};

... Hoàn toàn vô dụng vì bạn sẽ không bao giờ gọi hàm, và cái này ...

true/false ? alert('boo') : $.noop();

... thậm chí còn vô dụng hơn vì bạn gọi một hàm trống, nó hoàn toàn giống với ...

true/false ? alert('boo') : undefined;

Chúng ta hãy thay thế biểu thức ternary bằng một iftuyên bố để xem nó vô dụng đến mức nào:

if (true/false) {
    alert('boo');
} else {
    $.noop(); // returns undefined which goes nowhere
}

Bạn chỉ có thể viết:

if (true/false) alert('boo');

Hoặc thậm chí ngắn hơn:

true/false && alert('boo');

Để cuối cùng trả lời câu hỏi của bạn, tôi đoán "không hoạt động thông thường" là câu không bao giờ được viết.


1
Tuy nhiên đôi khi bạn phải cung cấp một chức năng. Ví dụ với lời hứa sau đó (fn, fn) đôi khi bạn muốn cung cấp chức năng thứ hai nhưng không phải chức năng đầu tiên. do đó, bạn cần một cái gì đó cho một người giữ chỗ ...mypromise.then($.noop, myErrorhandler);
John Henckel

3

Tôi sử dụng:

 (0); // nop

Để kiểm tra thời gian thực hiện của lần chạy này là:

console.time("mark");
(0); // nop
console.timeEnd("mark");

kết quả: đánh dấu: 0,000ms

Sử dụng Boolean( 10 > 9)có thể được giảm xuống chỉ đơn giản là ( 10 > 9)trả về true. Xuất hiện ý tưởng sử dụng một toán hạng đơn mà tôi hoàn toàn mong đợi (0);sẽ trả về false, nhưng nó chỉ đơn giản trả lại đối số như có thể được xem xét bằng cách thực hiện kiểm tra này tại bàn điều khiển.

> var a = (0);
< undefined
> a
< 0

1
nhiều người thử điều này sẽ nhận đượcargument 0 is not a function
Code Whisperer

4
Bạn chỉ cần gán 0. IMO noopsẽ là một hàm đánh giá undefinedkết quả.
cchamberlain

1
Tuyên bố này như thế nào (0); gán 0?, ở đâu là var và dấu bằng? Không có tên hàm ở phía trước (0), vì vậy tôi không thấy điều này có thể là một đối số như thế nào? nếu bạn thử typeof ((0)), nó sẽ trở lại dưới dạng số. Khi tôi trả lời câu hỏi, tôi đã cung cấp một tuyên bố mà tôi sử dụng để bắt chước một NOP, nhưng tôi sẵn sàng thay đổi câu trả lời của mình để sử dụng đơn giản; để thể hiện một tuyên bố trống rỗng
Trứng

1
Tôi nghĩ (0); là một giải pháp chấp nhận được cho câu hỏi của OP. Tôi nghĩ mọi người đang bối rối vì họ tìm thấy trang này trong khi tìm kiếm một chức năng không có gì, thay vì một tuyên bố không làm gì. OP không giúp đỡ bằng cách ban đầu đề xuất function(){}như một giải pháp. Gọi (0)()sẽ gây raTypeError: 0 is not a function
Benjamin

Tôi đã tham khảo var a = (0);. Một no-op không nên thay đổi bộ nhớ và ví dụ bài tập của bạn làm điều đó. Bản (0)thân nó có thể được coi là một no-op vô dụng (có vô số trong số này trong JavaScript vì vậy không có gì làm cho ví dụ của bạn ở đây trở nên đặc biệt).
cchamberlain

2

Hoàn toàn không có vấn đề hoặc hiệu suất phạt sử dụng Function.prototypehơn () => {}.

Lợi ích chính của Function.prototypeviệc có một chức năng đơn lẻ thay vì xác định lại một chức năng ẩn danh mới mỗi lần. Điều đặc biệt quan trọng là sử dụng no-op như Function.prototypekhi xác định các giá trị mặc định và ghi nhớ vì nó cung cấp cho bạn một con trỏ đối tượng nhất quán không bao giờ thay đổi.

Lý do tôi khuyên bạn Function.prototypehơn Functionlà vì chúng không giống nhau:

Function() === Function()
// false

Function.prototype() === Function.prototype()
// true

Ngoài ra, điểm chuẩn từ các câu trả lời khác là sai lệch . Trong thực tế, Function.prototypethực hiện nhanh hơn () => {}tùy thuộc vào cách bạn viết và chạy điểm chuẩn:

Bạn không thể tin tưởng điểm chuẩn JS << Cụ thể gọi ra điểm chuẩn cho câu hỏi này.

Đừng tạo kiểu cho mã của bạn từ điểm chuẩn; làm bất cứ điều gì có thể duy trì và để người phiên dịch tìm ra cách tối ưu hóa trong thời gian dài.

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.