2012-04-10 37 views
46

thể trùng lặp:
JavaScript: var functionName = function() {} vs function functionName() {}Có phải chức năng được đặt tên hoặc chức năng ẩn danh được ưa thích trong JavaScript không?

Có hai phương pháp có thể cho kéo ra một hàm trong Javascript:

var foo = function() { ... } 

(đây là một chút giả tạo; một mô hình phổ biến là:

var foo = { 
    baz: 43, 
    doSomething:function() { 
     ... 
    } 
} 

)

so

function foo() { ... } 

Có một lý do rõ ràng để thích một hay khác?

+0

Phạm vi của lần đầu tiên có khác biệt với giây không? –

+0

Đây là một bài viết hay http://kangax.github.com/nfe/ –

+0

@amnotiam: Đồng ý. Đã bỏ phiếu để đóng. –

Trả lời

66

Tất cả đều đi xuống đến sở thích đến nơi bạn khai báo các chức năng của mình; cẩu.

tờ khai Chức năng và khai báo biến luôn di chuyển ("treo") vô hình để phía trên cùng của phạm vi chứa của họ bằng cách thông dịch JavaScript. Các thông số chức năng và tên được xác định theo ngôn ngữ rõ ràng là đã có. Điều này có nghĩa rằng mã như thế này:

function foo() { 
    bar(); 
    var x = 1; 
} 

là thực sự giải thích như thế này:

function foo() { 
    var x; 
    bar(); 
    x = 1; 
} 

Chú ý rằng phần phân công của tờ khai không được kéo lên. Chỉ có tên được treo. Đây không phải là trường hợp với các khai báo hàm, trong đó toàn bộ thân hàm cũng sẽ được hoisted.

function test() { 
    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function() { // function expression assigned to local variable 'foo' 
     alert("this won't run!"); 
    } 
    function bar() { // function declaration, given the name 'bar' 
     alert("this will run!"); 
    } 
} 
test(); 

Trong trường hợp này, chỉ khai báo hàm có phần thân được treo lên trên cùng. Cái tên 'foo' được hoisted, nhưng cơ thể bị bỏ lại phía sau, được chỉ định trong khi thực hiện.

Bạn có thể cung cấp tên các chức năng được xác định trong các biểu thức chức năng, với cú pháp như một khai báo hàm. Điều này không làm cho nó một tuyên bố chức năng, và tên không được đưa vào phạm vi, cũng không phải là cơ thể hoisted.

foo(); // TypeError "foo is not a function" 
bar(); // valid 
baz(); // TypeError "baz is not a function" 
bin(); // ReferenceError "bin is not defined" 

var foo = function() {}; // anonymous function expression ('foo' gets hoisted) 
function bar() {}; // function declaration ('bar' and the function body get hoisted) 
var baz = function bin() {}; // named function expression (only 'baz' gets hoisted) 

foo(); // valid 
bar(); // valid 
baz(); // valid 
bin(); // ReferenceError "bin is not defined" 

Vì vậy, nếu bạn thích có chức năng Palăng đến việc sử dụng đầu một function declaration nếu không sử dụng expression. Tôi thích thứ hai như tôi thường xây dựng literals đối tượng với các phương thức như function expressions.

Đặt tên function expressions có thể có ích khi lỗi được ném. Giao diện điều khiển sẽ cho bạn biết những gì các chức năng là thay vì nêu anonymous aka stack trace.

+4

Chỉ cần nhớ rằng các khai báo hàm trong các khối là [không hợp lệ về mặt kỹ thuật] (http://stackoverflow.com/questions/4071292/may-function-declarations-appear-inside-statements-in-javascript), vì vậy nó có thể được ưa thích để sử dụng biểu thức hàm sau đó. –

+1

Ồ, rõ ràng là "khai báo hàm" không nên tồn tại/được xử lý đặc biệt trong javascript - chúng chỉ là một biểu thức, như "biểu thức hàm được đặt tên", có giá trị trả về bị bỏ qua. – masterxilo

+0

@ JesseGood — vâng vâng, ý tôi là bên trong * nếu * khối. Tôi sẽ sửa nó. – RobG

3

Có rất ít lợi thế chức năng đặt tên

  • tên để phân tích meta. functionInstance.name sẽ hiển thị cho bạn tên.
  • Quan trọng hơn, tên sẽ được in theo dấu vết ngăn xếp.Các tên
  • cũng giúp viết mã tự viết hoặc viết mã.

Có một nhược điểm duy nhất để chức năng đặt tên biểu thức

  • IE có rò rỉ bộ nhớ cho NFE

Không có nhược điểm để hoạt động khai ngoài việc kiểm soát ít phong cách

+0

Phiên bản nào của IE? 9? –

+0

IE <9. Các công cụ JScript cũ hơn, cũng là phiên bản Safari 2.1, Old opera, firefox cũ. Đọc bài viết của NFE – Raynos

0

của bạn câu hỏi thực sự bao gồm hai phần, vì bạn không nhất thiết phải làm cho các hàm của bạn ẩn danh nếu chúng được gán cho một biến hoặc thuộc tính.

Được đặt tên và ẩn danh?

@Raynos nêu bật những điểm chính rõ ràng. Phần tốt nhất về chức năng được đặt tên là họ sẽ hiển thị bản thân trong một dấu vết ngăn xếp. Ngay cả trong các tình huống mà các hàm đang được gán cho các biến/thuộc tính, bạn nên đặt tên cho hàm của bạn chỉ để hỗ trợ gỡ lỗi, tuy nhiên, tôi sẽ không nói các hàm ẩn danh là tà ác. Họ làm phục vụ cho một mục đích tốt đẹp: khai

Are anonymous functions a bad practice in JavaScript?

Function vs biểu hiện chức năng?

Đối với một phần của câu hỏi tôi sẽ giới thiệu bạn cho câu hỏi này vì nó có thể bao gồm các chủ đề sâu xa hơn tôi có thể

var functionName = function() {} vs function functionName() {}

9

Bạn đã nhấn vào một vài điều khác nhau ở đây , nhưng tôi sẽ cố gắng nhấn câu hỏi chính của bạn trước.

Nói chung ....

function() { ... } là một biểu chức năng. Về mặt pháp lý, giá trị này ở cùng mức với 2 hoặc [4,5]. Số này đại diện cho một giá trị . Vì vậy, việc thực hiện var foo=function(){ ... } sẽ hoạt động theo kế hoạch, mọi lúc.

function foo() { ... } là khai báo hàm. Điều này có vẻ tương tự như var foo=function(){...}, nhưng có một cảnh báo nhỏ. Như một tuyên bố của nó, nó hoạt động tương tự như khái niệm về biến hoisting trong JS (về cơ bản, tất cả các khai báo biến được thực hiện trước khi bất kỳ biểu thức nào được đánh giá).

Một ví dụ điển hình là từ here:

function test() { 
    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function() { // function expression assigned to local variable 'foo' 
     alert("this won't run!"); 
    } 
    function bar() { // function declaration, given the name 'bar' 
     alert("this will run!"); 
    } 
} 
test(); 

biến cơ bản cẩu đã mang lại giá trị lên đến đỉnh, do đó, mã này là tương đương (về mặt lý thuyết) tới:

function test() { 
    var foo;//foo hoisted to top 
    var bar=function(){//this as well 
     alert("this will run!"); 
    } 

    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function() { // function expression assigned to local variable 'foo' 
     alert("this won't run!"); 
    } 
} 

NB: Tôi muốn lấy chỗ này để nói rằng các thông dịch viên JS có một thời gian khó theo lý thuyết, vì vậy hãy tin tưởng họ vào một số hành vi xấu xa r không được khuyến cáo.Here bạn sẽ tìm thấy một ví dụ tốt ở phần cuối của một phần mà lý thuyết và thực hành kết thúc không hoạt động (cũng có thêm một số chi tiết về chủ đề của biểu thức vs khai báo).

Fun thực tế: gói function foo() {...} trong ngoặc biến nó từ một tuyên bố để một biểu thức, có thể dẫn đến một số mã nhìn lạ như

(function foo() { return 1; })();// 1 
foo; //ReferenceError: foo is not defined 

Đừng làm điều này nếu bạn không có một lý do để , xin vui lòng.


Tóm tắtvar foo=function(){ ... } là * sorta kinda * giống như chức năng foo(){ ... } ngoại trừ các cựu làm những gì bạn nghĩ rằng nó mà bạn nghĩ rằng nó nên trong khi sau này không những thứ kỳ lạ, trừ khi bạn quấn nó trong dấu ngoặc, nhưng điều đó làm rối loạn phạm vi và thông dịch viên JS cho phép bạn thực hiện những việc được coi là lỗi cú pháp trong thông số kỹ thuật, do đó bạn được cho là tin rằng những điều sai trái thực sự đúng, v.v.

vui lòng sử dụng chức năng biểu thức (var f=function(){...}). Không có lý do thực sự để không, đặc biệt là xem xét bạn đang phần nào buộc phải làm điều đó khi bạn đang sử dụng cú pháp chấm.


Bật để điều thứ hai bạn chạm vào .....

Tôi không thực sự chắc chắn phải nói gì, nó kinda sorta hoàn toàn khác biệt so với mọi thứ khác về vấn đề này.

var foo = { 
    baz: 43, 
    doSomething:function() { 
     ... 
    } 
} 

điều này được gọi là cú pháp ngữ của đối tượng. JSON, dựa trên cú pháp này, là a pretty neat way of formatting data và cú pháp này trong JS thường được sử dụng để khai báo các đối tượng mới, với các đối tượng đơn lẻ (ví dụ: tránh tất cả các mớ hỗn độn bằng cách khai báo hàm và sử dụng hàm mới). Nó cũng có thể được sử dụng trong cùng một XML cách được sử dụng, và được ưa thích bởi tất cả các trẻ em mát mẻ ...

Anyways, về cơ bản phản đối cú pháp đen làm việc như thế này:

{ name1: val1, .... namek:valk } 

biểu hiện này là một đối tượng với một số giá trị được khởi tạo trên đó. do đó, hãy thực hiện var obj={ name1: val1, .... namek:valk } có nghĩa là:

obj.name1==val1; 
obj['name1']==val1;// x['y'] is the same thing as x.y 
... 
obj.namek==valk; 

Vì vậy, điều này phải làm gì với ví dụ của chúng tôi? Về cơ bản, biểu thức của bạn thường được sử dụng để khai báo các đối tượng singleton. Nhưng nó cũng có thể được sử dụng để khai báo một nguyên mẫu đối tượng, vì vậy một người nào đó sau này có thể làm var newObj = Object.create (foo) và newObj sẽ có foo làm nguyên mẫu.

Xem xét tính kế thừa nguyên mẫu một cách chi tiết nếu bạn muốn thực sự có được mức độ hữu ích của nó. Douglas Crockford nói chi tiết về nó trong số one của nhiều cuộc nói chuyện của ông).

+0

Ví dụ 'var foo = {...' không phải là cú pháp JSON. Đó là cú pháp ngữ của đối tượng. Các ký hiệu cấu trúc dữ liệu của JSON là * dựa trên * đối tượng JavaScript và cấu trúc chữ mảng, nhưng chúng không giống nhau. –

+0

lưu ý, tôi đã cố gắng thay đổi các tham chiếu đến JSON đúng cách. Bạn có ví dụ về JSON không phải là cú pháp đúng ngữ pháp hay vise-versa? – rtpg

+0

Nói chung, nếu bạn định nghĩa một đối tượng theo nghĩa đen trong mã JavaScript, chúng tôi không gọi nó là JSON, vì phần còn lại của mã JS làm cho JSON không hợp lệ. Ngược lại, nếu chúng ta loại bỏ tất cả JS, và chỉ có một cấu trúc JSON độc lập như '{" foo ":" bar "}' (vì các khóa JSON phải được trích dẫn kép), đây không phải là một chương trình JavaScript hợp lệ. Kết quả sẽ là * SyntaxError *. Ngoài ra, có một số ký tự ẩn được cho phép trong chuỗi JavaScript, nhưng không được phép sử dụng JSON. Nhìn chung, kết nối duy nhất giữa JS và JSON là hai chữ cái đầu tiên và cú pháp * chung * của cấu trúc dữ liệu. –

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