chức năng javascript hàng đầu bang! cú pháp


204

Bây giờ tôi đã thấy cú pháp này trên một vài thư viện và tôi tự hỏi lợi ích là gì. (lưu ý rằng tôi biết rõ về việc đóng cửa và những gì mã đang làm, tôi chỉ quan tâm đến sự khác biệt về cú pháp)

!function(){
  // do stuff
}();

Là một thay thế cho phổ biến hơn

(function(){
  // do stuff
})();

để tự gọi các hàm ẩn danh.

Tôi đang tự hỏi một vài điều. Trước hết, điều gì cho phép ví dụ hàng đầu thực sự hoạt động? Tại sao tiếng nổ cần thiết để làm cho tuyên bố này đúng về mặt cú pháp? Tôi cũng nói rằng nó +hoạt động, và tôi chắc chắn một số người khác, thay cho!

Thứ hai, lợi ích là gì? Tất cả những gì tôi có thể nói là nó tiết kiệm được một nhân vật, nhưng tôi không thể tưởng tượng rằng đó là một lợi ích to lớn như vậy để thu hút nhiều người chấp nhận. Có một số lợi ích khác tôi đang thiếu?

Sự khác biệt duy nhất tôi có thể thấy là giá trị trả về của hàm tự gọi, nhưng trong cả hai ví dụ này, chúng tôi không thực sự quan tâm đến giá trị trả về của hàm vì nó chỉ được sử dụng để tạo một bao đóng. Vì vậy, ai đó có thể cho tôi biết tại sao người ta có thể sử dụng cú pháp đầu tiên?


Các khung làm việc muốn lưu càng nhiều ký tự càng tốt mà trình khai thác không thể tối ưu hóa.
alex

Lợi ích đầu tiên đến với tôi là bạn có thể tạo một hộp cát như, (function ($) {...}) (jQuery);
JS Taylor

2
cả hai ví dụ đều đạt được điều này. Như đã đề cập, tôi hiểu những chức năng này đang làm gì, tôi quan tâm nhiều hơn đến sự khác biệt về cú pháp
brad

8
Tôi cho rằng nó cần, nee, yêu cầu phải dễ thương theo cách tinh vi hơn so với phi hành đoàn trước đó. "Ồ, những người ngoại đạo đó, chúng ta đã có !!"
Jared Farrish

2
Tôi chưa bao giờ biết về điều này, tuyệt vời. Tôi thích !vì nó nhấn mạnh rằng nó đang được thực thi.
cdmckay

Câu trả lời:


97

Lý tưởng nhất là bạn có thể làm tất cả điều này đơn giản như:

function(){
  // do stuff
}(); 

Điều đó có nghĩa là khai báo hàm ẩn danh và thực thi nó. Nhưng điều đó sẽ không hoạt động do các chi tiết cụ thể của ngữ pháp JS.

Vì vậy, hình thức ngắn nhất để đạt được điều này là sử dụng một số biểu thức, ví dụ UnaryExpression (và vì vậy CallExpression):

!function(){
  // do stuff
}(); 

Hoặc cho vui:

-function(){
  // do stuff
}(); 

Hoặc là:

+function(){
  // do stuff
}(); 

Hoặc thậm chí:

~function(){
  // do stuff
  return 0;
}( );

3
Vì vậy, lợi ích duy nhất căng thẳng?
brad

12
Tôi đã thêm tất cả các tùy chọn ở trên vào kiểm tra hiệu suất tại: jsperf.com/bang-feft
Shaz

5
Biểu cảm tôi sẽ nói. Tốc độ không thực sự quan trọng trong những trường hợp như nó chạy một lần.
c-smile

1
Vì tò mò, tôi nhận thấy rằng không có tiếng nổ và tiếng nổ nào diễn ra nhanh nhất nhưng ít nhất ở đâu đó trong quá trình tiến hóa của Chrome, tiếng nổ trở nên nhanh hơn tiếng nổ. (Có lẽ không có ý nghĩa thống kê nhưng ...) Có lý do tại sao không? Tôi không biết nhiều về mã bên dưới mui xe nhưng thấy nó khá hấp dẫn.
jmk2142

Hai toán tử đơn nguyên của bạn có thể được hiểu là nhị phân nếu thiếu dấu chấm phẩy. Đầu tiên và cuối cùng là an toàn nhất trong những ví dụ.

73

Trong Javascript, một dòng bắt đầu bằng functionđược dự kiến ​​là một câu lệnh hàm và được cho là trông giống như

function doSomething() {
}

Một chức năng tự gọi như

function(){
  // do stuff
}();

không phù hợp với biểu mẫu đó (và sẽ gây ra lỗi cú pháp ở lần mở đầu tiên vì không có tên hàm), vì vậy dấu ngoặc được sử dụng để phân định biểu thức hàm ẩn danh .

(function(){
  // do stuff
})();

Nhưng bất cứ điều gì tạo ra một biểu thức (trái ngược với một câu lệnh hàm) sẽ làm, do đó, do đó !. Nó nói với người phiên dịch rằng đây không phải là một tuyên bố chức năng. Ngoài ra, ưu tiên toán tử ra lệnh rằng hàm được gọi trước khi phủ định.

Tôi đã không biết về quy ước này, nhưng nếu nó trở nên phổ biến thì nó có thể góp phần vào khả năng đọc. Điều tôi muốn nói là bất kỳ ai đang đọc !functionở đầu một khối mã lớn sẽ mong đợi một sự tự gọi, cách chúng ta được điều hòa đã mong đợi như vậy khi chúng ta nhìn thấy (function. Ngoại trừ việc chúng ta sẽ mất những dấu ngoặc đơn gây phiền nhiễu. Tôi hy vọng đó là lý do, trái ngược với bất kỳ khoản tiết kiệm nào về tốc độ hoặc số lượng nhân vật.


"Dòng bắt đầu với chức năng được mong đợi ..." trông khá mờ. Điều gì về điều này:var foo = {CR/LF here} function bar() {}
c-smile

45

Bên cạnh những điều đã được nói, cú pháp với! rất hữu ích nếu bạn viết javascript mà không có dấu chấm phẩy:

var i = 1
!function(){
  console.log('ham')
}()

i = 2
(function(){
  console.log('cheese')
})()

Ví dụ đầu tiên xuất ra 'ham' như mong đợi, nhưng ví dụ thứ hai sẽ đưa ra lỗi vì câu lệnh i = 2 không bị chấm dứt do dấu ngoặc đơn sau.

Ngoài ra, trong các tệp javascript được nối, bạn không phải lo lắng nếu mã trước đó thiếu dấu chấm phẩy. Vì vậy, không cần chung; (function () {}) (); để chắc chắn rằng bạn sẽ không phá vỡ.

Tôi biết câu trả lời của tôi là muộn nhưng tôi nghĩ nó chưa được đề cập đến :)


6
+1 cho mẹo và ký ức ... không ai thích viết javascript mà không có dấu chấm phẩy ngày nay.
Pablo Grisafi

4
Twitter Bootstrap là tất cả các JS không có dấu chấm phẩy và nó khá mới ... (xin lỗi nếu nhận xét trên có bản chất mỉa mai và tôi đã bỏ lỡ nó).
nhãn hiệu

2
Điều này không thực sự đúng. Hãy xem xét ví dụ sau :! Function () {console.log ("ham");} ()! Function () {console.log ("cheese")} (); bạn gặp lỗi: "Cú pháp: Mã thông báo bất ngờ!"
heavyysixer 2/213

Vâng, bạn đúng. Có lỗi, nếu bạn đặt chúng trên cùng một dòng. Tôi đã không nghĩ về điều đó. Nhưng, không có kịch bản ghép / lib tôi đã sử dụng cho đến nay làm điều đó. Và khi bạn thu nhỏ & concat, dấu chấm phẩy của bạn được thêm vào. Vì vậy, thành thật mà nói, tôi không thể tưởng tượng được một trường hợp bạn gặp phải vấn đề đó. Mặt khác, đã 2 giờ sáng ở đây và tôi có thể không biết gì :)
Smoe

6

Đối với một điều, jsPerf cho thấy rằng việc sử dụng !(UnaryExpression's) thường nhanh hơn. Đôi khi họ đi ra để được bình đẳng, nhưng khi họ không, tôi đã không nhìn thấy phi đập một chiến thắng quá nhiều so với những người khác được nêu ra: http://jsperf.com/bang-function

Điều này đã được thử nghiệm trên Ubuntu mới nhất với Chrome cũ nhất (mỗi lần nói ..), phiên bản 8. Vì vậy, kết quả có thể khác nhau tất nhiên.

Chỉnh sửa: Làm thế nào về một cái gì đó điên rồ như thế deletenào?

delete function() {
   alert("Hi!"); 
}();

hay void?

void function() {
   alert("Hi!"); 
}();

hấp dẫn! Tôi đã nhận được khoảng 50/50 mặc dù trong Safari tốc độ khôn ngoan, không đập chắc chắn được giữ riêng. Tôi tự hỏi nếu có một số lý thuyết cho sự khác biệt tốc độ tiềm năng?
brad

@brad Phải là một cái gì đó để làm với safari, nếu bạn nhìn vào các bài kiểm tra, hầu hết các trình duyệt khác dường như được ưa chuộng !. Nhưng tôi cũng muốn tìm một lý thuyết về điều này nữa :)
Shaz

3
Tôi thích void vì nó nói rõ ràng "tôi không quan tâm đến giá trị trả về" và bởi vì nó nhắc tôi về các quy ước trong các ngôn ngữ khác
code_monk

4

Như bạn có thể thấy ở đây , cách tốt nhất để thực hiện các phương thức tự gọi trong javascript là sử dụng:

(function(){}()); -> 76,827,475 ops/sec

!function(){}();  -> 69,699,155 ops/sec

(function(){})(); -> 69,564,370 ops/sec

1
Tôi nghi ngờ hiệu suất là lý do để sử dụng một cú pháp này hay cú pháp khác. Với tốc độ 70 triệu ops / giây, tuyên bố đóng cửa sẽ nhanh hơn hàng nghìn lần so với mã bên trong
Eloims

3

Vì vậy, với phủ định "!" và tất cả các toán tử đơn nguyên khác như +, -, ~, xóa, void, rất nhiều đã được nói, chỉ để tóm tắt:

!function(){
  alert("Hi!");
}(); 

Hoặc là

void function(){
  alert("Hi!");
}();

Hoặc là

delete function(){
  alert("Hi!");
}();

Và một vài trường hợp nữa với các toán tử nhị phân cho vui :)

1 > function() {
   alert("Hi!"); 
}();

Hoặc là

1 * function() {
   alert("Hi!"); 
}();

Hoặc là

1 >>> function() {
   alert("Hi!"); 
}();

Hoặc thậm chí

1 == function() {
   alert("Hi!"); 
}();

Rời khỏi chim nhạn cho người khác :)


12
0?0:function() { alert("Hi!"); }();
daniel1426

Chơi lô tô, Dân! Chúng ta có một
con chim nhạn
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.