2010-08-02 27 views
96

Gần đây tôi đã so sánh phiên bản hiện tại của json2.js với phiên bản tôi có trong dự án của mình và nhận thấy sự khác biệt về cách biểu thức hàm được tạo và tự thực thi.Vị trí của dấu ngoặc đơn để tự động thực thi các hàm JavaScript ẩn danh?

Các mã được sử dụng để bọc một chức năng ẩn danh trong ngoặc đơn và sau đó thực hiện nó,

(function() { 
    // code here 
})(); 

nhưng bây giờ nó kết thúc tốt đẹp các chức năng tự động thực hiện trong ngoặc đơn.

(function() { 
    // code here 
}()); 

Có một bình luận bởi CMS trong câu trả lời chấp nhận của Explain JavaScript’s encapsulated anonymous function syntax rằng “cả hai:. (function(){})();(function(){}()); có giá trị”

tôi đã tự hỏi những gì là sự khác biệt? Liệu các cựu mất bộ nhớ bằng cách để lại xung quanh một chức năng toàn cầu, vô danh? Dấu ngoặc đơn nên được đặt ở đâu?

+1

Xem thêm [Khác biệt giữa (hàm() {})(); và hàm() {}();] (http://stackoverflow.com/q/423228/1048572) và [Có sự khác nhau giữa (hàm() {…}()) hay không; và (function() {...})();?] (http://stackoverflow.com/q/3783007/1048572) – Bergi

+0

Liên quan: [Cú pháp gọi hàm hàm ngay lập tức] (http://stackoverflow.com/q/939386/1048572) (trong JSLint) – Bergi

+1

Cũng đọc về [mục đích của cấu trúc này] (http://stackoverflow.com/q/592396/1048572), hoặc kiểm tra ([technical] (http://stackoverflow.com/ q/4212149/1048572)) [giải thích] (http://stackoverflow.com/q/8228281/1048572) (cũng [ở đây] (http://stackoverflow.com/a/441498/1048572)). Vì lý do tại sao dấu ngoặc đơn là cần thiết, hãy xem [câu hỏi này] (http://stackoverflow.com/q/1634268/1048572). – Bergi

Trả lời

59

Chúng hầu như giống nhau.

Dấu ngoặc đơn đầu tiên bao quanh một hàm để làm cho nó trở thành một biểu thức hợp lệ và gọi nó. Kết quả của biểu thức là không xác định.

Thứ hai thực thi hàm và dấu ngoặc đơn xung quanh lời gọi tự động làm cho nó trở thành một biểu thức hợp lệ. Nó cũng đánh giá không xác định.

Tôi không nghĩ rằng có một cách "đúng" để làm điều đó, vì kết quả của biểu thức là như nhau.

> function(){}() 
SyntaxError: Unexpected token (
> (function(){})() 
undefined 
> (function(){return 'foo'})() 
"foo" 
> (function(){ return 'foo'}()) 
"foo" 
+8

JSLint muốn "(hàm() {}());". JSLint nói, "Di chuyển lệnh gọi vào các parens chứa hàm." – XP1

+26

Thực ra bạn không bị giới hạn ở hai thứ đó, bạn có thể sử dụng bất cứ thứ gì làm cho trình biên dịch nhận ra hàm là một phần của biểu thức chứ không phải một câu lệnh, chẳng hạn như hàm '+ function() {}()' hoặc '!) {}() '. – Tgr

+45

@ XP1: JSLint muốn nhiều thứ dành riêng cho phong cách * của Crockford * thay vì là nội dung. Đây là một trong số họ. –

13

Trong trường hợp đó không quan trọng. Bạn đang gọi một biểu thức giải quyết một hàm trong định nghĩa đầu tiên, và định nghĩa và ngay lập tức gọi một hàm trong ví dụ thứ hai. Chúng giống nhau vì biểu thức hàm trong ví dụ đầu tiên chỉ là định nghĩa hàm.

Có nhiều trường hợp rõ ràng là hữu ích khác cho cách gọi biểu thức giải quyết các chức năng:

(foo || bar)() 
+3

Để làm rõ cho người đọc khác (chủ yếu là bởi vì tôi không hiểu nó lúc đầu bản thân mình :)), foo và/hoặc thanh phải bằng một số chức năng. (ví dụ 'foo = function() {alert ('hi');}'. Nếu không phải là một hàm, một lỗi sẽ bị ném. –

+2

@AlexanderBird Làm rõ thêm - Nó cũng sẽ ném một lỗi nếu 'foo' là" trung thực "nhưng không phải là một chức năng. – JLRishe

7

Không có bất kỳ sự khác biệt vượt qua cú pháp.

Về mối quan tâm của bạn về phương pháp thứ hai để làm việc đó:

xem xét:

(function namedfunc() { ... }())

namedfunc sẽ vẫn không được trong phạm vi toàn cầu ngay cả khi bạn cung cấp tên. Cũng vậy với các chức năng ẩn danh. Cách duy nhất để có được nó trong phạm vi đó là gán nó cho một biến bên trong các parens.

((namedfunc = function namedfunc() { ... })()) 

Các dấu ngoặc bên ngoài là không cần thiết:

(namedfunc = function namedfunc() { ... })() 

Nhưng bạn không muốn điều đó tuyên bố toàn cầu anyways, cậu?

Vì vậy, nó nó nắm tới:

(function namedfunc() { ... })() 

Và bạn có thể giảm nó thậm chí còn hơn nữa: tên của nó là không cần thiết vì nó sẽ không bao giờ được sử dụng (trừ khi chức năng của bạn là đệ quy .. và thậm chí sau đó bạn có thể sử dụng arguments.callee)

(function() { ... })() 

Đó là cách tôi nghĩ về nó (có thể không đúng, tôi chưa đọc đặc tả ECMAScript). Hy vọng nó giúp.

-3

Sự khác biệt chỉ tồn tại vì Douglas Crockford không thích kiểu đầu tiên cho IIFEs! (seriuosly) As you can see in this video!!.

Lý do duy nhất cho sự tồn tại của gói thêm () {trong cả hai phong cách} là giúp làm cho điều đó phần mã Chức năng biểu, vì Function Tuyên bố không thể ngay lập tức gọi. Một số tập lệnh/minify-ers chỉ sử dụng +, !, - & ~ thay vì quá dấu ngoặc đơn. Như thế này:

+function() { 
    var foo = 'bar'; 
}(); 

!function() { 
    var foo = 'bar'; 
}(); 

-function() { 
    var foo = 'bar'; 
}(); 

~function() { 
    var foo = 'bar'; 
}(); 

Và tất cả những điều này hoàn toàn giống với lựa chọn thay thế của bạn. Chọn trong số các trường hợp này hoàn toàn nằm trên & của riêng bạn sẽ không tạo ra sự khác biệt nào. {Những người có () sản xuất 1 Tập tin lớn hơn byte ;-)}

Các vấn đề liên quan