簡體   English   中英

JavaScript 關閉 - 怎么了?

[英]Closure in JavaScript - whats wrong?

我試圖通過關閉來制作下一個:

function func(number) {
    var result = number;

    var res = function(num) {
        return result + num;
    };
    return res;
}

var result = func(2)(3)(4)(5)(3);
console.log(result); // 17

我需要收到 2 + 3 + 4 + 5 + 3 = 17 但我收到一個錯誤:未捕獲的 TypeError: number is not a function

您必須以某種方式指示鏈的末端,您將在此處返回結果編號而不是另一個函數。 你有選擇:

  • 讓它返回一個固定次數的函數——這是像你一樣使用語法的唯一方法,但它很無聊。 看看@PaulS 的回答。 您可以使第一次調用 ( func(n) ) 提供curried參數sum的數量。
  • 在某些情況下返回結果,例如在不帶參數(@PaulS 的第二個實現)或帶有特殊值(@AmoghTalpallikar 的答案中為null )的情況下調用函數時。
  • 在函數對象上創建一個返回值的方法。 valueOf()非常適合,因為它會在函數被轉換為原始值時被調用。 看看它在行動:

     function func(x) { function ret(y) { return func(x+y); } ret.valueOf = function() { return x; }; return ret; } func(2) // Function func(2).valueOf() // 2 func(2)(3) // Function func(2)(3).valueOf() // 5 func(2)(3)(4)(5)(3) // Function func(2)(3)(4)(5)(3)+0 // 17

你在濫用你的功能。

func(2)返回res函數。
使用(3)調用該函數會返回數字5 (通過return result + num )。

5不是函數,所以(4)給出錯誤。

好吧,(2)(3)部分是正確的。 調用 func(2) 將返回res ,這是一個函數。 但是,調用 (3) 將返回res的結果,這是一個數字。 因此,當您嘗試調用 (4) 時,問題就來了。

對於您正在嘗試做的事情,我看不出 Javascript 如何預測您處於鏈的末端,並決定返回一個數字而不是一個函數。 也許您可以使用對象屬性以某種方式返回一個具有“結果”屬性的函數,但大多數情況下,我只是好奇您為什么要以這種方式做事。 顯然,對於您的具體示例,最簡單的方法就是將數字相加,但我猜您會更進一步。

如果你想繼續調用它,你需要不斷返回一個函數,直到你想要你的答案。 例如 5 次調用

function func(number) {
    var result = number,
        iteration = 0,
        fn = function (num) {
            result += num;
            if (++iteration < 4) return fn;
            return result;
        };
    return fn;
}
func(2)(3)(4)(5)(3); // 17

你也可以做一些像這樣工作的更多長度

function func(number) {
    var result = number,
        fn = function () {
            var i;
            for (i = 0; i < arguments.length; ++i)
                result += arguments[i];
            if (i !== 0) return fn;
            return result;
        };
    return fn;
}
func(2)(3, 4, 5)(3)(); // 17

我將其標記為重復,但由於該問題也缺少此替代方案,因此我將在此處添加它。 如果我理解正確,為什么您會認為這很有趣(將任意函數順序應用於值列表,累積結果),您還應該研究reduce

function sum(a, b) {
    return a + b;
}

a = [2, 3, 4, 5, 3];

b = a.reduce(sum);

另一種解決方案可能只是調用不帶參數的函數以獲得結果,但如果你使用參數調用它,它會增加總和。

 function add() { var sum = 0; var closure = function() { sum = Array.prototype.slice.call(arguments).reduce(function(total, num) { return total + num; }, sum); return arguments.length ? closure : sum; }; return closure.apply(null, arguments); } console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)); // function(){} console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)()); // 30;

我們可以使用幾個輔助函數identitysumk

sumk使用延續來保留一個待處理的添加計算的堆棧,並在調用 first ()時用0展開堆棧。

 const identity = x => x const sumk = (x,k) => x === undefined ? k(0) : y => sumk(y, next => k(x + next)) const sum = x => sumk(x, identity) console.log(sum()) // 0 console.log(sum(1)()) // 1 console.log(sum(1)(2)()) // 3 console.log(sum(1)(2)(3)()) // 6 console.log(sum(1)(2)(3)(4)()) // 10 console.log(sum(1)(2)(3)(4)(5)()) // 15

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM