2013-08-15 31 views
16

Có thể bất kỳ ai giải thích cách chức năng này cảnh báo, khi không có dấu ngoặc nào của thông số được chuyển. Tôi không thể hiểu rõ.Đóng cửa bằng Javascript với nhiều dấu ngoặc đơn

function sum(a) { 

    var sum = a 

    function f(b) { 
    sum += b 
    return f 
    } 

    f.toString = function() { return sum } 

    return f 
} 

alert(sum(1)(2)) // 3 
alert(sum(5)(-1)(2)) // 6 
alert(sum(6)(-1)(-2)(-3)) // 0 
alert(sum(0)(1)(2)(3)(4)(5)) // 15 

Trả lời

16

Lần đầu tiên chức năng của bạn được gọi, giá trị đầu tiên được lưu trữ trong sum. Sau đó function f(b) sẽ được trả lại, duy trì kết quả tạm thời trong sum. Với mỗi lần gọi liên tiếp, bạn thực hiện chức năng f - bạn thực hiện sum += b và trả lại f lần nữa. Nếu bối cảnh chuỗi là bắt buộc (chẳng hạn như trong số alert hoặc console.log) f.toString được gọi thay thế, trả lại kết quả (sum).

function sum(a) { 

    var sum = a 

    function f(b) { 
    sum += b 
    return f //<- from second call, f is returned each time 
       // so you can chain those calls indefinitely 
       // function sum basically got "overridden" by f 
    } 

    f.toString = function() { return sum } 

    return f //<- after first call, f is returned 
} 

Giải thích:

alert(sum(6)(-1)(-2)(-3)) // 0 
      /\ function sum called, f returned 
       /\ the returned function f is called, f returns itself 
        /\ again 
        /\ and again 
         /\ at last, alert() requires string context, 
          so f.toString is getting invoked now instead of f 
+0

Về cơ bản trong tổng cảnh báo đầu tiên (1) (2) là a & b và trong cảnh báo thứ hai là tổng (6) (- 1) (2) bây giờ cách hàm hiểu rằng (2) cũng là f (b) tranh luận. – PCA

+0

@Babu loại bỏ suy nghĩ của a và b. Bạn có thể nghĩ rằng 'sum()' được gọi một lần, khởi tạo 'var sum' và sau đó nhận được overriden sau cuộc gọi đầu tiên, xử lý từng cuộc gọi liên tiếp bằng cách gọi' f (b) '(vì f chính nó mỗi lần trả về chính nó, do đó làm cho nó có thể làm thêm chuỗi) chức năng trừ khi một bối cảnh chuỗi xảy ra. Rõ ràng hơn bây giờ? – Christoph

+0

giải thích tuyệt vời. Bạn có thể vui lòng cho tôi biết thay vì f.toString bạn có thể chỉ cho tôi mã để trả lại số tiền trực tiếp không. chức năng sum (a) { var sum = a hàm f (b) { sum + = b trở lại sum } // f.toString = function() {return sum} trở lại f } tổng (1) (2); – PCA

2

alert mong đợi một chuỗi. Nếu nó không nhận được một chuỗi, nó sẽ cố gắng chuyển đổi bất kỳ đối tượng nào nó nhận được (và một hàm là một loại đối tượng) thành một. Nếu đối tượng có phương thức toString thì phương thức đó sẽ được gọi để thực hiện chuyển đổi đã nói.

+2

Tất cả các đối tượng đều có hàm 'toString', chỉ trong hầu hết các trường hợp là định dạng" [Constructorname] "mặc định. Trong trường hợp này, phương thức đó được ghi đè để tạo kết quả. –

3

Những điều cần xem xét là đoạn mã này

function f(b) { 
    sum += b 
    return f 
    } 

Hàm này trả về tham chiếu đến chính nó để nó có thể được gọi là nhiều lần càng tốt. Một điều quan trọng về nó là nó có một hàm toString đó được gọi và kể từ toString được định nghĩa bên trong chức năng sum() nó có quyền truy cập vào biến sum và giá trị hiện tại giá trị của nó (có nghĩa là thay đổi bằng cách f())

1

Các sumf các hàm luôn trả về hàm f, bạn có thể gọi nó là vô hạn lần mà không nhận được kết quả nào ngoài hàm.

Giá trị chỉ được trả về bởi các toString phương pháp ghi đè của f (mà thực sự trả về một số):

console.log(sum(1)(2)) // Function(){} 
console.log(sum(1)(2).toString()) // 3 

Chức năng alert ngầm gọi phương thức toString khi nó phôi đối số của nó để chuỗi.

0

Nó không làm việc như mong muốn trong tất cả các trường hợp ... Vấn đề là .toString dự kiến ​​sẽ trả về một chuỗi, vì vậy phương pháp chuỗi trong việc thực hiện cung cấp, sẽ không hoạt động, e. g. sum(2)(3).split() sẽ gây ra lỗi.

Mặc dù chúng tôi có thể giả định kết quả sum() sẽ luôn được mong đợi là một số, nhưng có thể không đúng trong một số trường hợp và có thể khó gỡ lỗi, e. g. Tôi nhận thấy vấn đề khi tôi đã thử nghiệm mã ban đầu được viết với .toString chỉ trên jsbin.com (nó split trên đối số console.log nội bộ, ghi đè nó).

Thay vào đó, .toString sẽ trông giống như return String(result);. Điều tốt là .toString (khi không có .valueOf hoặc hiện đại Symbol.toPrimitive) sẽ xử lý chuyển đổi nguyên thủy, do đó, mã mong đợi một Số cũng sẽ hoạt động. Vấn đề có thể xảy ra ở đây có thể là chuyển đổi "gấp đôi" do điều này.

Giải pháp tốt hơn có thể là sử dụng một trong hai cặp .toString.valueOf hoặc chỉ một Symbol.toPrimitive nếu bạn chỉ nhắm mục tiêu các trình duyệt hiện đại.

Ví dụ sử dụng Symbol.toPrimitive:

function sum(a) { 
    let result = a; 

    function f(b) { 
    result += b; 

    return f; 
    } 

    f[Symbol.toPrimitive] = hint => hint === 'string' ? String(result) : result; 

    return f; 
} 

Ví dụ sử dụng .toString.valueOf cặp.

function sum(a) { 
    var result = a; 

    function f(b) { 
    result += b; 

    return f; 
    } 

    // avoiding double conversion which will happen in case of .toString 
    f.valueOf = function() { return result; }; 
    f.toString = function() { return String(result); }; 

    return f; 
} 
Các vấn đề liên quan