2011-11-14 37 views
10

Tôi đã đọc một số sách JavaScript và tôi luôn nghe về các bao đóng và tác dụng phụ. Vì một lý do nào đó tôi không thể hiểu họ thực sự là gì. Bất cứ ai có thể giải thích cho tôi những gì họ đang ở trong tiếng Anh đơn giản cộng với ví dụ? (như bạn đã giải thích nó cho ai đó với cấp độ lập trình của một nhà thiết kế đồ họa).Đóng cửa Javascript và tác dụng phụ bằng tiếng Anh đơn giản? (riêng)

+0

Vui lòng làm rõ: Bạn có yêu cầu giải thích về việc đóng cửa và riêng biệt cho một lời giải thích về tác dụng phụ không? Hoặc về cả hai kết hợp? – delnan

+0

@delnan xin lỗi tôi đã sửa đổi tiêu đề. – alexchenco

+1

Sau đó xem http://stackoverflow.com/questions/111102/how-do-javascript-closures-work và xóa phần đóng, nó sẽ là một bản sao. Tác dụng phụ không hoàn toàn mới, nhưng tôi không biết gì về SO, vì vậy tôi không bỏ phiếu để đóng ngay bây giờ. – delnan

Trả lời

12

Tác dụng phụ là những khái niệm dễ dàng hơn. Một "hàm thuần túy" là một hàm ánh xạ (các) giá trị đầu vào của nó vào một giá trị đầu ra def plus(x, y){ return x + y; }. "Hiệu ứng phụ" là bất kỳ hiệu ứng nào khác ngoài giá trị trả về đó. Vì vậy, ví dụ:

def plusWithSideEffects(x, y) { alert("This is a side effect"); return x + y; } 

có tác dụng phụ khi nâng cao hộp thoại cảnh báo (và yêu cầu tương tác người dùng). Mỗi chức năng mã có một số hiệu ứng phụ (tất cả đều tiêu thụ bộ nhớ và mất thời gian, nếu không có gì khác), nhưng khi mọi người nói về tác dụng phụ, họ thường quan tâm nhất với IO (như hộp thoại cảnh báo ở trên) hoặc bằng văn bản trạng thái vượt quá thời gian thực thi của hàm.

Thách thức với các tác dụng phụ là chúng làm cho các chức năng khó hơn để lý luận và tái sử dụng. (Đó là dễ dàng hơn để lý trí và chức năng tái sử dụng mà là càng gần đến "chức năng thuần túy" càng tốt, vì họ có xu hướng "làm một điều tốt.")

+1

Đối với "cấp độ lập trình của một nhà thiết kế đồ họa", đó là câu trả lời thực sự. –

+0

Tôi không bỏ phiếu này vì câu trả lời không trả lời câu hỏi, nhưng, tôi không thích từ khóa def được sử dụng trong ví dụ vì nó không phải là một từ dành riêng javascript, đó là một điều python phải không? – zappa

0

dụ

function outer() { 
    var outerVar; 

    var func = function() { 
     var innerVar 
     ... 
     x = innerVar + outerVar 
    } 
    return func 
} 

Khi bên ngoài() chết, chức năng Func() tiếp tục livе và sử dụng này thực tế

2

Side-hiệu lực:

nghĩ đến một dụng phụ có hiệu lực như một cái gì đó làm hai thứ cùng một lúc. Ví dụ:

cổ điển ví dụ về một tác dụng phụ:

var i = 1; 
var j = i++; 

Các tác dụng phụ xảy ra tại i++. Chuyện gì xảy ra ở đây là j trở thành 1 và sau đói được tăng lên và trở thành 2. Nói cách khác, có hai điều xảy ra và các tác dụng phụ là i trở thành 2.

Đóng cửa:

Hình dung một chuỗi các các liên kết như thế này: <> <> <> <> <> <> <>. Hãy tưởng tượng rằng tên của chuỗi liên kết này được gọi là chuỗi phạm vi . Sau đó, hãy tưởng tượng rằng tất cả các liên kết này kết nối các đối tượng với nhau như sau: <> đối tượng <> đối tượng <> đối tượng <>. Bây giờ, hãy ghi nhớ những điều sau:

(1) Tất cả chuỗi phạm vi bắt đầu với đối tượng toàn cầu.

(2) Khi hàm được xác định, chuỗi phạm vi cho chức năng đó được lưu trữ.

(3) Khi hàm được gọi, nó tạo đối tượng mới và thêm đối tượng đó vào chuỗi phạm vi.

Bây giờ, hãy nhìn vào ví dụ sau:

function counter() { // define counter 
        var count = 0; 
        return function() { return count + 1;}; // define anonymous function 
        }; 
var count = counter(); // invoke counter 

Trong ví dụ này, khi counter() được xác định, chuỗi phạm vi cho quầy trông như thế này: <> toàn cầu đối tượng <>. Sau đó, khi counter() được gọi, chuỗi phạm vi trông giống như sau: <> đối tượng toàn cầu <> đối tượng truy cập <>. Sau đó, hàm không có tên (được gọi là hàm ẩn danh) bên trong bộ đếm được định nghĩa và được gọi. Chuỗi phạm vi chức năng ẩn danh khi gọi ngoại hình như thế này:. <> toàn cầu đối tượng <> truy cập đối tượng <> đối tượng chức năng ẩn danh <>

Heres được phần đóng cửa do thỏa thuận Nếu bạn nhận thấy, các chức năng ẩn danh đang sử dụng biến số count được xác định bên ngoài nó. Lý do là vì chức năng ẩn danh có thể truy cập bất kỳ biến nào được xác định trong chuỗi phạm vi. Đây là những gì một đóng cửa, một hàm cùng với các tham chiếu đến bất kỳ biến nào trong chuỗi phạm vi được lưu trữ của nó.

Tuy nhiên, trong ví dụ trên, khi các hàm trả về, các đối tượng được tạo tại lời gọi bị hủy bỏ để thực sự không có điểm. Bây giờ nhìn vào những điều sau đây:

function counter() { // define counter 
        var count = 0; 
        function f() { return count + 1;}; // define f 
        return f; // return f 
        }; 
var count = counter(); // invoke counter 

Trong ví dụ này, tôi đang trở về một hàm có tên f và gán vào biến count. Bây giờ biến số count giữ một tham chiếu đến toàn bộ chuỗi phạm vi và nó không bị loại bỏ. Nói cách khác, số biến lưu trữ chuỗi phạm vi như sau: <> đối tượng toàn cầu <> đối tượng truy cập <> đối tượng hàm ẩn danh <>. Đây là sức mạnh của bao đóng, bạn có thể giữ một tham chiếu đến một chuỗi phạm vi, và gọi nó như thế này: count().

+1

** Phần đóng của câu trả lời này không chính xác **. JavaScript có * phạm vi tĩnh *, có nghĩa là chuỗi phạm vi của một hàm được định nghĩa ở hàm * định nghĩa *, ** không ** hàm * gọi *. Ví dụ này hoạt động vì hàm ẩn danh được định nghĩa mỗi khi 'counter' được gọi, nghĩa là mỗi hàm trả về sẽ có một chuỗi phạm vi với một đối tượng * kích hoạt khác nhau * cho' counter', và do đó một tập hợp các biến cục bộ khác (chẳng hạn như 'count'). [Xem câu trả lời này để biết thêm thông tin.] (Http://stackoverflow.com/questions/7721200/using-javascript-closures-in-settimeout/7722057#7722057) – josh3736

+0

@ josh3736: Cảm ơn bạn đã bình luận. Tôi đã thay đổi câu trả lời của mình, vui lòng cho biết nếu có điều gì sai. Ngoài ra, tôi muốn bình luận rằng, đối với một khai báo hàm toàn cầu, hàm sẽ chỉ có một tham chiếu đến một chuỗi phạm vi có chứa đối tượng toàn cầu. Không cho đến khi bạn gọi nó sẽ có tham chiếu đến đối tượng kích hoạt. –

4

Các chức năng có tác dụng phụ làm điều gì đó khác ngoài việc trả về một giá trị (mặc dù chúng cũng có thể làm điều đó). Nếu bạn có thể thay thế tất cả các cuộc gọi hàm cho các đối số đã cho bằng giá trị cho các đối số đó và chương trình có cùng hành vi, không có tác dụng phụ. Điều này yêu cầu hàm luôn trả về cùng một giá trị cho các đối số đã cho.

Tức là, giả sử f(1,2) == 12. Nếu bạn luôn có thể thay thế f(1,2) bằng 12 và chương trình hoạt động theo cách tương tự, thì f không có tác dụng phụ cho các đối số đó. Mặt khác, nếu ở một nơi f(1,2) == 12 và một số khác là f(1,2) == 13 thì f có các tác dụng phụ. Tương tự, nếu chương trình ngừng gửi email sau khi thay thế f(1,2) bằng 12, thì f có các tác dụng phụ. Nói chung, nếu f(x,y) == z (trong đó z phụ thuộc vào x và y) và bạn luôn có thể thay thế mọi cuộc gọi f(x,y) với z, sau đó f không có phản ứng phụ.

Một số chức năng đơn giản với tác dụng phụ:

// doesn't always return the same value 
function counter() { 
    // globals are bad 
    return ++x; 
} 
// omitting calls to `say` change logging behavior 
function say(x) { 
    console.log(x); 
    return x; 
} 
0

Tôi mới vào JavaScript, và sẽ không cố gắng nói chuyện đóng cửa. Tuy nhiên, tính mới của tôi đối với JavaScript khiến tôi khá ý thức về việc sử dụng các hiệu ứng phụ không thể thực hiện được trong ngôn ngữ lập trình thông thường của tôi (Erlang).

Tác dụng phụ dường như là cách thông thường để thay đổi trạng thái trong JavaScript. Lấy ví dụ ví dụ này từ trang web của w3cschools.com:

<script> 
function myFunction() { 
    document.getElementById("demo").innerHTML = "Paragraph changed."; 
} 
</script> 

Ở đây không có thông số đầu vào hoặc giá trị trả về, thay vì nội dung của các tài liệu có được thay đổi vì họ là toàn cầu trong phạm vi chức năng. Ví dụ, nếu bạn đã viết nó trong Erlang, tài liệu sẽ được truyền vào như một tham số, và trạng thái tài liệu mới sẽ được trả về. Một người đọc chương trình gọi điện thoại sẽ thấy một tài liệu được chuyển vào và một tài liệu bị thay đổi đang được trả lại.

Xem các chức năng được gọi là không trả về trạng thái mới rõ ràng nên cảnh báo cho lập trình viên về việc sử dụng các tác dụng phụ có thể xảy ra.

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