《1》首先是惰性函數javascript
惰性載入表示函數執行的分支只會在函數第一次掉用的時候執行,在第一次調用過程當中,該函數會被覆蓋爲另外一個按照合適方式執行的函數,這樣任何對原函數的調用就不用再通過執行的分支了。php
看下面典型的例子:html
爲了兼容各瀏覽器,對事件監聽的的支持:java
function addEvent (type, element, fun) {
if (element.addEventListener) {
element.addEventListener(type, fun, false);
}
else if(element.attachEvent){
element.attachEvent('on' + type, fun);
}
else{
element['on' + type] = fun;
}
}web
上面是註冊函數監聽的各瀏覽器兼容函數。因爲,各瀏覽之間的差別,不得不在用的時候作能力檢測。顯然,單從功能上講,已經作到了兼容各瀏覽器。可是,每次綁定監聽,都會對能力作一次檢測,這就沒有必要了,真正的應用中,這顯然是多餘的,同一個應用環境中,只須要檢測一次便可。ajax
因而有了以下改變:數組
function addEvent (type, element, fun) {
if (element.addEventListener) {
addEvent = function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if(element.attachEvent){
addEvent = function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else{
addEvent = function (type, element, fun) {
element['on' + type] = fun;
}
}
return addEvent(type, element, fun);
}瀏覽器
能夠看出,第一次調用addEvent會對瀏覽器作能力檢測,而後,重寫了addEvent。下次再調用的時候,因爲函數被重寫,不會再作能力檢測。閉包
相似的例子還有:XMLHttRequest:app
function createXHR() { 4 var xhr; 5 try{ 6 xhr = new XMLHttpRequest(); 7 }catch(e) { 8 handleErr(e); 9 10 try { 11 xhr = new ActiveXObject("Msxml2.XMLHTTP"); 12 }catch(e) { 13 try{ 14 xhr = new ActiveXObject("Microsoft.XMLHTTP"); 15 }catch(e) { 16 xhr = null; 17 } 18 } 19 } 20 21 return xhr ; 22 } 23 24 function handleErr(error) { 25 // 這一步在實戰中很重要,由於catch會延長做用域鏈,因此是在全局做用域聲明的e 26 // 這裏咱們把它賦給局部變量,則查找更快 27 var err = error; 28 29 // do sth. 30 }
因爲不一樣的瀏覽器的xmlhttpreque對象的不一樣形式,爲了兼容一樣要在使用ajax時判斷,但一樣這樣的判斷只需一次。
看惰性函數優化後:
function createXHR() { 5 var xhr; 6 if(typeof XMLHttpRequest != 'undefined') { 7 xhr = new XMLHttpRequest(); 8 createXHR = function() { 9 return new XMLHttpRequest(); 10 } 11 }else { 12 try { 13 xhr = new ActiveXObject("Msxml2.XMLHTTP"); 14 createXHR = function() { 15 return new ActiveXObject("Msxml2.XMLHTTP"); 16 } 17 }catch(e) { 18 try { 19 xhr = new ActiveXObject("Microsoft.XMLHTTP"); 20 createXHR = function() { 21 return new ActiveXObject("Microsoft.XMLHTTP"); 22 } 23 }catch(e) { 24 createXHR = function () { 25 return null; 26 } 27 } 28 } 29 } 30 return xhr 31 }
代碼中,咱們讓函數在第一次運行以後,則判斷除了瀏覽器的環境,就被從新賦值了。
賦值後的函數是直接return 對應的方法。因此,這個函數,須要第二次調用的時候才真正的被調用。
正是由於它第二次調用函數的時候,沒有去走第一次調用那樣複雜的判斷的路,因此顯得「懶惰」。所以咱們叫它 惰性函數
能夠總結出在哪些狀況下使用惰性函數:
1 應用頻繁,若是隻用一次,是體現不出它的優勢出來的,用的次數越多,越能體現這種模式的優點所在;
2 固定不變,一次斷定,在固定的應用環境中不會發生改變;
《2》函數柯里化
關於這個看了好多資料,其實仍是並無很懂,<攤手>
直接上代碼:
// //函數柯里化
1》提升適用性:
【通用函數】解決了兼容性問題,但同時也會再來,使用的不便利性,不一樣的應用場景往,要傳遞不少參數,以達到解決特定問題的目的。有時候應用中,同一種規則可能會反覆使用,這就可能會形成代碼的重複性。
function square(i) {
return i * i;
}
function dubble(i) {
return i *= 2;
}
function map(handeler, list) {
return list.map(handeler);
}
// 數組的每一項平方
map(square, [1, 2, 3, 4, 5]);
map(square, [6, 7, 8, 9, 10]);
map(square, [10, 20, 30, 40, 50]);
// ......
// 數組的每一項加倍
map(dubble, [1, 2, 3, 4, 5]);
map(dubble, [6, 7, 8, 9, 10]);
map(dubble, [10, 20, 30, 40, 50]);
函數柯里化改造後:
function curry(fn){
var args=Array.prototype.slice.call(arguments,1);
console.log(args);//輸出:function aquare(){...}
return function(){
var innerArgs=Array.prototype.slice.call(arguments);
console.log(innerArgs);//輸出:1,2,3,4,5
var finalArgs=args.concat(innerArgs);
console.log(finalArgs);//輸出:function square(){},1,2,3,4,5
return fn.apply(null,finalArgs);
}
}
function square(i) { return i * i; }
function dubble(i) { return i *= 2; }
function map(handeler, list) { return list.map(handeler); }
var mapSQ = curry(map, square);
mapSQ([1, 2, 3, 4, 5]);
mapSQ([3,2,5,7,6,7]);
var mapDB = curry(map, dubble);
mapDB([1, 2, 3, 4, 5]);
mapDB([2,5,7,6,2,3]);
柯里化一般也稱部分求值,其含義是給函數分步傳遞參數,每次傳遞參數後部分應用參數,並返回一個更具體的函數接受剩下的參數,這中間可嵌套多層這樣的接受部分參數函數,直至返回最後結果。
所以柯里化的過程是逐步傳參,逐步縮小函數的適用範圍,逐步求解的過程。
var currying = function (fn) {
var _args = [];
return function () {
if (arguments.length === 0) {
return fn.apply(this, _args);
}
Array.prototype.push.apply(_args, [].slice.call(arguments));
return arguments.callee;
}
};
var multi=function () {
var total = 0;
for (var i = 0, c; c = arguments[i++];) {
total += c;
}
return total;
};
var sum = currying(multi);
sum(100,200)(300);
sum(400);
console.log(sum()); // 1000 (空白調用時才真正計算)
上面的代碼實際上是一個高階函數(high-order function), 高階函數是指操做函數的函數,它接收一個或者多個函數做爲參數,並返回一個新函數。此外,還依賴與閉包的特性,來保存中間過程當中輸入的參數。即:
var addEvent = function(el, type, fn, capture) {
if (window.addEventListener) {
el.addEventListener(type, function(e) {
fn.call(el, e);
}, capture);
} else if (window.attachEvent) {
el.attachEvent("on" + type, function(e) {
fn.call(el, e);
});
}
};
每次添加事件處理都要執行一遍 if...else...,其實在一個瀏覽器中只要一次斷定就能夠了,把根據一次斷定以後的結果動態生成新的函數,之後就沒必要從新計算。
var addEvent = (function(){
if (window.addEventListener) {
return function(el, sType, fn, capture) {
el.addEventListener(sType, function(e) {
fn.call(el, e);
}, (capture));
};
} else if (window.attachEvent) {
return function(el, sType, fn, capture) {
el.attachEvent("on" + sType, function(e) {
fn.call(el, e);
});
};
}
})();
《3》級聯函數
!--JavaScript級聯函數--> <!--本課時介紹JavaScript級聯函數, 級聯函數也叫鏈式函數,方法鏈一 般適合對一個對象進行連續操做 (集中在一句代碼)。必定程度上 能夠減小代碼量,缺點是它佔用了 函數的返回值。-->
function myclassA(){
this.name="";
this.age="";
this.sex="";
}
myclassA.prototype={
setname:function(){
this.name="katherine";
return this;
},
setage:function(){
this.age="22";
return this;
},
setsex:function(){
this.sex='girl';
return this;
}
}
var me =new myclassA();
console.log(me.setname().setage().setsex());
// myclassA {name: "katherine", age: "22", sex: "girl"}
參考自http://www.tuicool.com/articles/N7Z3qey,
參考:
http://sombie.diandian.com/post/2013-06-28/40050585369
http://book.2cto.com/201211/9320.html
http://zh.wikipedia.org/wiki/Currying
http://www.ibm.com/developerworks/cn/web/1006_qiujt_jsfunctional/
http://www.cnblogs.com/lwbqqyumidi/archive/2012/12/03/2799833.html
純屬我的學習參考資料