JS 中 var add=function(){} add(a)(b)(c); 是什麼簡寫?

當時我就暈了,方法後面可以跟無限個()嗎?

網上搜了一下,大概明白了什麼匿名函數之類的,還不是太懂!


這種寫法存在多種可能性。簡單來說就是 add(a) 返回了一個函數,而將 b 作為參數去調用那個函數,又返回一個函數。

但是我來列舉一下常見的兩種情況吧。

在第一種情況下,後面不能跟無限個();在第二種情況下,後面可以跟無限個()。

情形 1:Currying

1.1 舉例

var add = function(x) { return function(y) { return function(z) { return x + y + z; } } }

var result = add(1)(2)(3); // result 是 6

1.2 解釋

var return_1 = add(1);

return_1 是 function(y) { return function(z) { return 1 + y + z; } }。

var return_2 = return_1(2);

return_2 是 function(z) { return 1 + 2 + z; };注意,return_2 也就是 add(1)(2)。

var result = return_2(3);

result 實際上是 1 + 2 + 3,也就是 6。注意,result 也就是 return_1(2)(3),所以也就是 add(1)(2)(3)。

1.3 關於 Currying

這實際上就是 currying(柯里化),也就是把一個多變數的函數變成一系列單變數的函數。每個函數接收一個參數,然後返回一個接收餘下參數並返回結果的新函數。這個過程中利用了閉包(closure)。也就是說,這種情況下,是一個函數返回另一個函數

比如上面的例子里,add 接受參數 x 並返回 return_1,return_1 接受參數 y 並返回 return_2,return_2 接受參數 z 並返回最終的值。

Currying 實際上是一個很漂亮的技術,你可以給一個參數固定一個參數後再把返回值(也就是接受剩餘參數的函數)作為參數傳遞給其它函數。在 JavaScript 這種重度依賴對回調函數(callback)的使用的語言中,確實能有一些幫助。

既然 Currying 可以看作是把 f(x, y) -&> z 變換成 f(x) -&> (f(y) -&> z),那麼很明顯,後面是不可能跟無限個 () 的;每個 () 只是確定了 Uncurry 之後的函數一個參數而已;並且每個參數的含義是彼此不同的。最多能有幾個 (),也就取決於 Uncurry 之後的函數有幾個參數。

情形 2:函數本身的鏈式操作

2.1 本質

一個函數返回函數本身。這種情況下,實際上 a(param) 返回的依然是 a。也就是,你可以無限地在後面追加對這個函數的調用。

比如

a(param_1)(param_2)(param_3)

實際上不過是

a(param_1);
a(param_2);
a(param_3);

的簡寫而已,沒有任何不同。

這樣做的前提是, a 函數返回 a 本身。每次 () 的含義是完全一樣的,每個 () 里的參數的含義自然也是完全一樣的。

2.2 更實際的例子

var el = document.getElementsByTagName("body")[0];

var append = function(html) { el.innerHTML += html; return append; }

append("I &hate& jQuery")(" really ")(" much ");

2.3 延伸:多個函數的例子

實際上你也可以是有 a、b 兩函數;a 函數返回 b,b 函數返回 a。如此,你就可以 a(1)(2)(3)(4)。也就相當於 a(1); b(2); a(3); b(4);

當然你也可以有三個或者四個函數互相返回彼此;甚至一個函數 a 根據輸入的參數決定返回 b 或是 c。然後 b 和 c 又返回 a 等等……


在代碼里看到這種代碼,自己沒法短時間看懂的,要是沒有特別特定的作用,建議學習了原理後,千萬別在代碼中模仿


function add(val){

function _retFun(v){

return add(val+v);

}

_retFun.toString = _retFun.valueOf = function(){return val;};

return _retFun;

}


一樓的親,大概的思路是對的,但是舉例很不恰當,幾乎無可復用性。如果這樣寫的函數,也就是add後面能且只能帶三個括弧,換句話說,就是一個、兩個、四個括弧都是不可以的。

其實這種技術用在add加法函數也不是很恰當的,因為正常邏輯上,只需要一次調用(即一個括弧)即可,比如這樣:add(1, 2, 3)。

如果一定要這樣調用:add(1)(2)(3)

就只能像一樓那樣寫了。但是編寫函數的有一個出發點就是要有良好的復用性。

順便提一下連著寫括弧的思路就是:執行到每一個括弧就是一次函數調用,想要後面再接括弧,就要想好前一個函數的返回值是什麼。

如果還有問題可以密我哦?


add(1)(2)(3)

等價於

var r1 = add(1);

var r2 = r1(2);

var r3 = r2(3);

也就是每一個()調用函數之後,返回值也是一個函數。

那麼有可能這個add方法內部是這樣的

1. //function1

var add = function(a) {

//function2

return function(b) {

//function3

return function(c) {

};

};

};

這樣的話

add(1)(2)(3)

第一個括弧調用的是function1,返回值是function2

第二個括弧調用的是function2,返回值是function3

第三個括弧調用的是function3

這樣的寫法如果後面再要繼續加括弧的話,那麼方法裡面要繼續按照這個格式寫function4 5 6.。

只能在最後一個function裡面寫上return 結果值

//function 最後一個

return a+b+c+.....+z;

或者用一個全局變數result來存儲計算結果,每一次調用方法都更新這個全局變數

//function xxx

return function(abc){

result = ......;//一系列計算

//function xxx+1

return function(abcd){

...

};

};

或者add方法是這樣的:

2.var add = function(num) {

if (typeof(result) == "undefined") {

result = 0

}

result += num;

console.error(result);

return add;

};

這樣的話

add(1)(2)(3)

每一次括弧的調用,返回值都是add自己本身,也就是說每一次調用都是調用的同一個函數。

這種寫法的好處就是可以在後面無限制的加上()而不需要再改寫add方法。

但是同樣想取得最終結果,需要用一個全局變數來存儲結果。

在 add(1)(2)(3);執行之後 用alert(result); 來查看結果。

知乎處女答。。。

大神求輕拍


就是函數curry化,後面應該有個空的(),作為函數運行的標誌

add(1)

此調用返回一個function([1]){arguments.sum()}

add(1)(2)

此調用返回一個function([1,2]){arguments.sum()}

add(1)(2)(3)

此調用返回一個function([1,2,3]){arguments.sum()}

然後add(1)(2)(3)()便是函數運行,可以點擊以下鏈接看示例

JS Bin - Collaborative JavaScript Debugging


推薦閱讀:

匿名函數的this指向為什麼是window?
HTML中的html head body標籤有且只能有一個,為什麼不可以直接省略?
bootstrap 用來構建大型互聯網網站前端布局可行性如何?
如何招到一個優秀的前端工程師?
Web 前端的未來會怎樣?

TAG:前端開發 | JavaScript |