問題:我們有一個需求,用js 實現一個無限極累加的函數, 形如 add(1) //=> 1; add(1)(2) //=> 2; add(1)(2)(3) //=> 6; add(1)(2)(3)(4) //=> 10; 以此類推。。。。。
乍一看很神奇, 下面我將一步一步實現一個這樣的 add()函數。
第一步:首先, 我們要了解一個知識點: 函數的 toString()方法當我們直接alert() 一個函數的時候會被調用(或者 用 console.log() 打印一個函數的時候會被調用)。
舉一個例子:
function s(a){ return a+1; } alert(s);
第二步:好的,我們現在對函數 s 定義一個 toSting() 方法
function s(a){ return a+1; } s.toString = function(){return 2;} console.log(s); typeof(s)
定義了s.toString 方法后, 直接console.log(s) 的話,會打印出這個函數, 如果直接 alert(s)的話,我們可以看到會彈出 “2”, 我們檢測一下s 的類型(typeof(s)),
顯然 s 是一個函數。
第三步:好的,現在我們來給這個 s 函數包裹上一層"外套" -:)
function add(a){ function s(a){ return a+1; } s.toString = function(){return a;} return s; } console.log(add(3));
在上面的代碼中,我們給之前的代碼 包裹了一層,並且也修改了一下s.toSting() 方法,讓它返回的是外面傳遞進來的參數a, 而不是之前固定的2。
包裹了一層后,返回值為一個函數,這樣就形成了一個閉包。 這樣,我們在調用 add(3) 的時候,返回值其實是一個函數, 里面的 s 這個函數。
但是,當我們 alert(s(3)) 的時候, 會彈出 3 。
第四步:好的,下面是最后一步,“見證奇跡的時刻到了”————
function add(a){ function s(b){ a = a+b; return s; } s.toString = function(){return a;} return s; } console.log(add(1)(2)(3)(4));
到這里,我們可以看到,上面 console.log(add(1)(2)(3)(4)); 這句話打印出 一個函數, function 10 , 其實就是當 alert(add(1)(2)(3)(4));的時候,會彈出 10.
這就是 add(1)(2)(3)(4); 的實現過程,顯然,我們這個累加函數是可以無限調用的 。-:) 小開心一下哈
下面,我來談一談個人的思路和理解,還望大家能踴躍參數, 幫忙指點我一下,不甚感激!
我覺得:整個實現過程就是兩個關鍵點。
1. 使用閉包, 同時要對JavaScript 的作用域鏈(原型鏈)有深入的理解;
2. 重寫函數的 toSting()方法;
好的,對add(1)(2)(3); 一步一步分析:
a) 執行add(1);
返回的是里面的 s 函數, 通過閉包,s 函數里面可以訪問到 變量 a=1; 所以 當我們 alert(add(1)); 的時候, 調用的 toSting()方法會將作用域(原型鏈)里面的 a = 1 彈出來。
b) 執行add(1)(2);
<===等價於===> s(2); 這里面相當於 把 2 傳遞給 s()函數里面的 b , 讓作用域(原型鏈)里面的 a = a+b ,此時 a = 3, 繼續保存在作用域中了。 然后還是返回 s 函數。
c) 執行 add(1)(2)(3);
<===等價於===> s(3);和上面 b) 中的分析一樣,只是更新了作用域中的 a = 6 了,然后同樣是返回 s 函數。