2013-04-16 32 views
8

Trong nhiều cuốn sách là gì/blog posts tự gọi mô hình chức năng ẩn danh được viết như thế này:sự khác biệt giữa những người tự thực hiện chức năng ẩn danh (aka IIFE) thực hiện

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

Tuy nhiên chạy một JSLint về điều này mang lại cho này lỗi:

Move the invocation into the parens that contain the function.

ví dụ: thay đổi nó để làm việc này:

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

Câu hỏi

  1. Tại sao là việc thực hiện đầu tiên không đủ tốt cho JSLint? Sự khác biệt là gì?
  2. Biểu mẫu ưa thích là gì? JSLint có đúng không?
  3. Tại sao nó hoạt động? sau khi tất cả function(){}() ném SyntaxError: Unexpected token (
    Nhưng gói nó với parens làm cho nó tất cả của một công việc đột ngột? ví dụ. (function(){}()) - hoạt động tốt
    (Sau khi tất cả điều này là JavaScript, không Lisp, vì vậy những gì là hiệu ứng của gói Parens về lỗi cú pháp ohterwise?)

EDIT: đây là một phần của một followup này (tôi sẽ không nói chính xác mặc dù): JSLint error: "Move the invocation into the parens that contain the function", vì vậy câu hỏi chính của tôi là # 3, tại sao nó hoạt động ở tất cả?

+2

Nhiều, nhiều bản sao. Tóm lại, 1-2: Bởi vì Crockford thích vậy. JSHint được tạo ra chỉ vì JSLint quá thiên vị. 3. Bởi vì định danh là tùy chọn cho các biểu thức hàm trong khi nó là bắt buộc đối với một khai báo hàm (các parens làm cho nó trở thành một biểu thức hàm). Xem http://kangax.github.io/nfe/#expr-vs-decl –

+0

Tôi không sử dụng JSLint. Nếu bạn làm, hãy hiểu nó là một công cụ thiên vị. I * thích * sử dụng liên tục biểu mẫu '; (hàm ..)()' - hàng đầu ';' ngăn chặn một lỗi có thể mơ hồ hơn. Cả hai biểu mẫu đều dẫn đến các cây cú pháp tương đương. – user2246674

+3

@ user2246674 Bạn đã nhập sai chữ H cho chữ L chưa? ': P' –

Trả lời

5

Tôi không biết ý kiến ​​của Crockford đã được phát triển như thế nào, nhưng tôi có thể giải thích lý do tại sao đóng gói trong tác phẩm parens.

Cú pháp hàm function() { ... } trong JavaScript có thể đại diện cho hai thứ khác nhau: khai báo hàm hoặc biểu thức hàm.

Tuyên bố hàm là câu lệnh xác định hàm trong phạm vi hiện tại dưới tên được chỉ định.

function example() { 
    alert("Hello World"); 
} 

example(); 

Một biểu hiện chức năng là một biểu hiện rằng để đánh giá một Function dụ mới.

var secondExample = function example() { 
    alert("Hello World"); 
}; 

secondExample(); 
example(); // <-- throws an Error: example is not defined. 

Việc xảy ra cú pháp là khai báo hàm hay câu lệnh hàm phụ thuộc vào những gì trình phân tích cú pháp mong đợi. Trình phân tích cú pháp của JavaScript rất đơn giản. Nó sẽ không nhìn về phía trước và nhận thấy rằng hàm được theo sau bởi (), do đó nó sẽ coi nó như là một biểu thức. Nó chỉ thấy function ở đầu dòng, và do đó xử lý nó như là một tuyên bố, gây ra lỗi cú pháp khi nó được theo sau bởi (). Khi bạn quấn nó trong dấu ngoặc đơn, trình phân tích cú pháp thay vì mong đợi một biểu thức và nó hoạt động.

Gói trong dấu ngoặc đơn (bất cứ nơi nào bạn đặt chúng) là cách rõ ràng nhất để làm điều này, nhưng bất kỳ điều gì làm cho trình phân tích cú pháp mong đợi một biểu thức sẽ hoạt động.Ví dụ, Bitwise NOT hành ~:

~function() { 
    alert("Hello World"); 
}(); 
+0

Cả hai mẫu được hiển thị là một FunctionDeclaration và trong khi điều này không địa chỉ # 3, nó thực sự đi trên một ốp .. – user2246674

+1

Tôi không hiểu làm thế nào đầu tiên không phải là một FunctionDeclaration. Per [the spec] (http://www.ecma-international.org/ecma-262/5.1/#sec-13), một FunctionDeclration là 'function Identifier (FormalParameterListopt) {FunctionBody}', và ví dụ của tôi phù hợp. –

+1

'(hàm() {})()' (dạng đầu tiên) so với'(function() {}())' (dạng thứ hai) so với 'function() {}()' (trong câu hỏi # 3). Tất nhiên câu hỏi # 3 không giải quyết bối cảnh như 'x = function() {}()' một lần nữa sẽ hợp lệ (và không phải là một FunctionDeclaration). – user2246674

1

1.

Rõ ràng đây là một vấn đề với các công ước. Có ví dụ đầu tiên cho thấy "thiếu quy ước" (source). Theo như sự khác biệt thực tế, không có gì. Cả hai sẽ thực thi mà không có lỗi.

2.

Trong trường hợp này, tôi thích ví dụ đầu tiên của bạn, nhưng đó chỉ là quy ước của tôi. JSLint thường đúng. Vì vậy, nếu bạn muốn thực hiện theo quy ước đặt tên của họ thì khi nó hiển thị một cảnh báo dựa trên quy ước, nó sẽ có ý nghĩa để phù hợp với quy ước.

3.

này hoạt động vì gói các function(){} bên trong một () làm cho nó một biểu thức, trong đó một lần kết hợp với trận chung kết () ngay lập tức gọi nó. Do đó bạn có một biểu thức hàm được gọi ngay lập tức.

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