摘要:自執(zhí)行函數閉包實現模塊化以樂之名程序員產品經理對作用域,以及閉包知識還沒掌握的小伙伴,可回閱前端進擊的巨人三從作用域走進閉包。參考文檔利用閉包實現模塊化翻譯淺談中的高階函數系列更文請關注專欄前端進擊的巨人,不斷更新中。。。
系列更文前三篇文章,圍繞了一個重要的知識點:"函數"。
函數調用棧、函數執(zhí)行上下文、函數作用域到閉包??梢姴焕斫夂瘮凳骄幊蹋a都擼不好。
函數與其它數據類型一樣,可以作為值賦給變量,作為參數傳遞或返回值返回,也可以像對象一樣給函數創(chuàng)建屬性(不推薦給函數加屬性,雖然可用)。
函數在實際開發(fā)中應用:函數聲明
函數表達式
匿名函數
自執(zhí)行函數
// 函數聲明 function getName() { //... } // 函數表達式 var getName = function() { //... } // 匿名函數 setTimeout(function(){ //... }, 1000); // 自執(zhí)行函數 (function(){ //... })();何為一等:優(yōu)先級
函數聲明在"執(zhí)行上下文創(chuàng)建階段"就會進行聲明并賦值,而var聲明變量會初始化為undefined,實際賦值會等到"執(zhí)行上下文執(zhí)行階段"。函數表達式使用var來聲明,因此它遵循的是變量聲明的規(guī)則。( 如果函數名與變量重名,函數優(yōu)先賦值)
"函數聲明優(yōu)先級高于變量聲明和函數表達式,自稱一等公民。"
// 代碼書寫: console.log(getName); getName(); var getName; getName = "我的名字"; function getName(){ //... } console.log(getName); // 實際執(zhí)行 var getName; // 變量名與函數名重名,函數優(yōu)先賦值 function getName() { //... } console.log(getName); getName(); getName = "我的名字"; console.log(getName);函數式編程
函數式編程是一種編程思維方式,它建議我們在程序編寫時,對復用性高的功能代碼進行函數封裝,實現代碼的高復用性。
新手朋友往往是一塊代碼多次出現在不同的地方,常見的例子就是ajax請求方法運用,在需要請求后端數據時多次出現一串ajax請求代碼。
如果想要對ajax請求統(tǒng)一做異常處理,或管理后端返回狀態(tài)碼,是不是每處代碼都要修改???但是如果把ajax請求代碼封裝成一個函數,接口url和數據data通過參數傳遞到函數內部處理,后期擴展維護都方便修改,復用性擴展性都更加優(yōu)秀。
所以實際敲代碼過程中,要經常提醒自己運用函數式編程的思維方式,只要有可能出現多次的業(yè)務邏輯代碼,那么就要考慮是否封裝成函數,以便后續(xù)統(tǒng)一調用。
function sumScore(list) { var totalScore = 0 for (var i = 0; i < list.length; i++) { totalScore += list[i]; } return totalScore; } var list = [10, 8, 9, 7]; var totalScore = sumScore(list); // 計算總分
TIPS: 函數名建議使用動詞,如addUser(),sumScore(),getUser()...
純函數純函數:相同的輸入對應相同的輸出,穩(wěn)定沒有副作用(不改變外部變量的值)相同的輸入,相同的輸出
相同的參數傳入調用,要有相同的結果輸出,概念有點繞,上代碼栗子:
function getDate() { return new Date(); } var dateOne = getDate(); var dateTwo = getDate(); var dateThr = getDate();
上述代碼中調用了三次getDate(),三次返回的值都不一樣。相同的輸入并沒有相同的輸出,所以getDate()并不是一個純函數。
TIPS:函數中使用new Date(),Math.random(), 異步等都可能造成函數不穩(wěn)定。
沒有副作用(不改變外部環(huán)境的值)部分小伙伴的代碼,在函數里面直接修改參數的值,這是一種非常不推薦的做法,這樣做會造成代碼環(huán)境不可控制,污染外部變量環(huán)境,一旦出現錯誤排查起來:心累,三個字心好累。
函數有自己的局部作用域,因此函數中,對需要使用到的變量,管控在自身的作用域下。如果需要修改外部參數的值,通過函數返回值返回給函數調用者。修改外部參數值的操作不在函數內進行,確保對外部環(huán)境沒有副作用。
TIPS:參數為引用類型時,參數復制的是地址指針,避免修改了引用類型中屬性值污染外部環(huán)境,如需使用建議手動深拷貝賦值。
function getGirlGift(list) { // 避免污染參數為引用類型的list,對list深拷貝 var newList = JSON.parse(JSON.stringify(list)); newList.map(girl => { girl.gift = girl.age > 18 ? "lipstick" : "chocolates"; }); return newList; // 返回新值 } var girlList = [ {name: "Kelly", age: 20}, {name: "Alic", age: 16}, {name: "Moon", age: 23}, {name: "Nana", age: 17} ]; var girlGiftList = getGirlGift(girlList); girlList // 原用girlList不變 girlGiftList // 每個girl多了gift屬性Array對象的函數(純與不純)
// 不純的函數 array.push(); // 數組尾部插入 array.pop(); // 刪除并返回數組最后一個元素 array.unshift(); // 數組頭部插入 array.shift(); // 刪除并返回數組第一元素 array.splice(); // 刪除元素,并向數組添加元素 array.reverse(); // 顛倒數組元素的順序 array.sort(); // 排序數組元素 // 純函數 array.slice(); // 數組中返回選定的元素 array.concat(); // 連接數組,并發(fā)揮新數組 array.join(); // 按分隔符連接數組,返回字符串
>>更多Array對象方法,參考W3C
純函數的應用:狀態(tài)管理Redux,Vuex流行框架中狀態(tài)管理就是純函數的實踐應用,引用redux的應用,reducer中返回新的狀態(tài)數據state,但不能去直接去修改state數據,以下為redux中reducer的例子代碼:
export default (state = defaultState, action) => { let newState = JSON.parse(JSON.stringify(state)); switch (action.type) { case DELETE_TODO_ITEM: newState.list.splice(action.value, 1); break; case ADD_TODO_ITEM: if (newState.inputValue.trim().length) { newState.list.push(newState.inputValue); } newState.inputValue = ""; break; case INIT_LIST_ACTION: newState = action.data break; default: break; } return newState; }"自執(zhí)行函數 +?閉包" 實現模塊化 模塊化包括:
私有變量
私有方法
公有變量
公有方法
上篇中《前端進擊的巨人(三):從作用域走進閉包》我們講解了作用域、閉包的原理機制。
"自執(zhí)行函數可實現塊級作用域,而閉包則可實現外部環(huán)境對函數作用域內部數據的訪問。"
// 自執(zhí)行函數 + 閉包實現模塊化 (function MakeModule(window) { var name = "以樂之名"; var age = 28; var job = "程序員"; function changeJob(newJob) { job = newJob; } function getName() { return name; } window.modulePublic = { changeJob: changeJob, getName: getName } })(window); window.modulePublic.getName(); window.modulePublic.changeJob("產品經理");
對作用域,以及閉包知識還沒掌握的小伙伴,可回閱《前端進擊的巨人(三):從作用域走進閉包》。
高階函數高階函數是一個函數,它接收函數作為參數或將函數作為輸出返回
JavaScript中常用的高階函數:
Array.prototype.map (映射遍歷)
Array.prototype.filter (過濾)
Array.prototype.reducer(累計)
除了內置的高階函數,我們實際開發(fā)中,高階函數應用的最多就是回調函數了。
function getOrder(url, datas, callBack) { return $.post(url, datas, callBack(orderInfo)); } // getOrder就是一個高階函數,接收callBack函數作為參數
高階函數的概念很簡單,"本身是函數,參數是函數,或返回值是函數"。
參考文檔:
JavaScript利用閉包實現模塊化
【翻譯】 - 淺談JavaScript中的高階函數
系列更文請關注專欄:《前端進擊的巨人》,不斷更新中。。。
本文首發(fā)Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂之名
本文原創(chuàng),有不當的地方歡迎指出。轉載請指明出處。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/101284.html
摘要:有關函數柯里化的詳解,請回閱前端進擊的巨人五學會函數柯里化。構造函數中的通過操作符可以實現對函數的構造調用。在了解構造函數中的前,有必要先了解下實例化對象的過程。 showImg(https://segmentfault.com/img/bVburMp?w=800&h=600); 常見this的誤解 指向函數自身(源于this英文意思的誤解) 指向函數的詞法作用域(部分情況) th...
摘要:在中,通過棧的存取方式來管理執(zhí)行上下文,我們可稱其為執(zhí)行棧,或函數調用棧。而處于棧頂的是當前正在執(zhí)行函數的執(zhí)行上下文,當函數調用完成后,它就會從棧頂被推出理想的情況下,閉包會阻止該操作,閉包后續(xù)文章深入詳解。 寫在開篇 已經不敢自稱前端小白,曾經吹過的牛逼總要一點點去實現。 正如前領導說的,自己喝酒吹過的牛皮,跪著都得含著淚去實現。 那么沒有年終完美總結,來個新年莽撞開始可好。 進擊巨...
摘要:除了以上介紹的幾種對象創(chuàng)建方式,此外還有寄生構造函數模式穩(wěn)妥構造函數模式。 showImg(https://segmentfault.com/img/remote/1460000018196128); 面向對象 是以 對象 為中心的編程思想,它的思維方式是構造。 面向對象 編程的三大特點:封裝、繼承、多態(tài): 封裝:屬性方法的抽象 繼承:一個類繼承(復制)另一個類的屬性/方法 多態(tài):方...
摘要:函數柯里化是把支持多個參數的函數變成接收單一參數的函數,并返回一個函數能接收處理剩余參數,而反柯里化就是把參數全部釋放出來。但在一些復雜的業(yè)務邏輯封裝中,函數柯里化能夠為我們提供更好的應對方案,讓我們的函數更具自由度和靈活性。 showImg(https://segmentfault.com/img/bVburN1?w=800&h=600); 柯里化(Curring, 以邏輯學家Has...
摘要:中有三種數據結構棧堆隊列。前端進擊的巨人一執(zhí)行上下文與執(zhí)行棧,變量對象中解釋執(zhí)行棧時,舉了一個乒乓球盒子的例子,來演示棧的存取方式,這里再舉個栗子搭積木。對于基本類型,棧中存儲的就是它自身的值,所以新內存空間存儲的也是一個值。 面試經常遇到的深淺拷貝,事件輪詢,函數調用棧,閉包等容易出錯的題目,究其原因,都是跟JavaScript基礎知識不牢固有關,下層地基沒打好,上層就是豆腐渣工程,...
閱讀 3171·2021-09-08 10:43
閱讀 1097·2019-08-30 15:53
閱讀 1097·2019-08-30 13:51
閱讀 925·2019-08-29 14:03
閱讀 876·2019-08-26 18:35
閱讀 1295·2019-08-26 13:38
閱讀 1680·2019-08-26 10:34
閱讀 3579·2019-08-26 10:21