JS 中 var add=function(){} add(a)(b)(c); 是什麼簡寫?
當時我就暈了,方法後面可以跟無限個()嗎?
網上搜了一下,大概明白了什麼匿名函數之類的,還不是太懂!
這種寫法存在多種可能性。簡單來說就是 add(a) 返回了一個函數,而將 b 作為參數去調用那個函數,又返回一個函數。
但是我來列舉一下常見的兩種情況吧。
在第一種情況下,後面不能跟無限個();在第二種情況下,後面可以跟無限個()。
情形 1:Currying1.1 舉例var add = function(x) { return function(y) { return function(z) { return x + y + z; } } }
var result = add(1)(2)(3); // result 是 6
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 xxxreturn 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 |