摘要:閉包與柯里化閉包有權訪問另一個函數作用域中變量的函數。柯里化把接受多個參數的函數變換成接受一個單一參數最初函數的第一個參數的函數,并且返回接受余下的參數而且返回結果的新函數的技術。
本回內容介紹
上一回聊到JS的Object類型,簡單模擬了一下Java的Map,介一講,偶們來聊一下函數好唔好,介可系JS世界的一等公民喲。從函數開始,我們就將逐步過渡到設計模式,來吧,帥狐帶你裝逼帶你飛:
1. 函數的定義方式有三種(1) 函數聲明:
function o(a,b){ return a+b; }
(2) 函數表達式:
var o = function(a,b){ return a+b; };
(3) 構造函數式:
var o = new Function("a","b","return a+b");
這里簡單的過一下函數定義,其他函數相關的基礎知識還是那句:請參閱書籍或其他資料。
2. call, apply, bind這仨都可以改變函數內部作用域的指向,bind()是ES5的新玩意兒,IE9以下不支持。call()和apply()一塊兒說,這倆基友僅僅是傳參不一樣而已,apply傳遞的是數組:
function add(arg1,arg2) { return arg1+arg2; }; function subtraction(arg1,arg2) { return arg1-arg2; }; function optCall(arg1,arg2){ return add.call(this,arg1,arg2); }; function optApply(arg1,arg2){ return subtraction.apply(this,[arg1,arg2]); }; alert(optCall(1,2)); // 3 alert(optApply(2,1)); // 1
再來說說bind(),在高程3(JavaScript高級程序設計第三版)書上的說法是:bind()常常和回調函數與事件處理程序一起使用以便在將函數作為變量傳遞的同時保留代碼執行環境。后面的設計模式講解中我們會有事件的講解,這里我們用書上的例子來模擬bind()的實現:
function bind(fn,context){ // 這里是一個閉包 return function(){ // 這里調用傳遞的函數,并將參數傳入 return fn.apply(context,arguments); }; }
這里光看例子可能有點抽象,沒關系,后面講設計模式,聊到觀察者模式的時候還會聊到事件。
3. 閉包與柯里化閉包:有權訪問另一個函數作用域中變量的函數。這是書上的解釋,有點懵吧,說白了,就是方法里面的方法就叫閉包。
柯里化:把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。
之所以把這倆放在一起來聊,是因為這倆都不好理解,有點繞,而且柯里化依賴于閉包來實現,來吧,直接看書上的例子:
var c = console; function curry(fn){ // 這個地方是獲取Array原型的slice方法,之所以這么用,是因為數組未被實例化之前,無法獲得原型上的方法,可能有點繞,先不管原型后面會講 var _slice = Array.prototype.slice; // 這里獲取的是傳入的第二個參數,也就是5 var args = _slice.call(arguments,1); c.log(args); // [5] // 這里是一個閉包,這個函數的作用是組合外部傳參和內部傳參 return function(){ // 在這里傳入的arguments是[15,10] var innerArgs = _slice.call(arguments); c.log(innerArgs); // [15,10] var finalArgs = args.concat(innerArgs); // 內外部數組合并 c.log(finalArgs); // [5,15,10] // 這里寫null或是其他都可以,因為這里只是執行傳入的方法,也就add()方法 return fn.apply(null,finalArgs); }; } function add(a,b,c){ return a+b+c; } alert(curry(add,5)(15,10));
很多盆友說這個例子木有看懂,現在配上了注釋,趕腳有木有好點。這里沒有多帶帶聊閉包,因為網上關于閉包的資料已經很多了。
順便在啰嗦一句,有哥們兒面試問到了,fn.apply(null,finalArgs)這里如果是null的話,指向的是什么?答案是Global,而在瀏覽器環境下,Global就是window。
又是裝逼時刻了,好咯,開始敲代碼了:
某客面試題,正好復習函數柯里化這一回講的內容比較繞腦袋,其實所有的函數都是Function類型的實例。一時理解不了也沒關系,先囫圇吞棗,后面的內容還會涉及,下面還是進入做題環節:
據說這家公司筆試題有四道題,這里先聊兩道題,另外了道題后面會聊到...
1.題目:five(one(one())) 返回 511function one(){ var tags = typeof arguments[0]; // 獲取傳入的第一個參數類型 var arg = ""; switch(tags){ // 判斷如果是undefined,說明是最里層的函數 case "undefined": arg = 1+""; break; // 判斷如果是string,說明已經執行過最里層函數了,也就是說,已經跑過case為"undefined"的情況了 case "string": arg = 1+arguments[0]; break; }; return arg; }; function five(){ return 5+arguments[0]; }; alert(five(one(one()))); alert(five(one(one(one(one(one(one())))))));
這個例子并非柯里化的函數,因為每一次one()的返回都是一個字符串,但是對比函數柯里化,使函數柯里化的概念更直觀了。
我們把這個five()改改,讓他變為柯里化,讓帥狐show給你看:
function five(){ var args = arguments[0]; // 這里就是一個閉包的體現,然后自執行,返回的依然是字符串 return (function(){ return 5+args; })(); };
怎么樣,帥吧!好吧,如果不帥,繼續下一題,走你:
2. 題目:數組去重、并按倒數第二個字母排序function unique(arr) { // res是結果數組,o是一個對象,上一回已經講過了,對象的key是不可重復的 var res = [], o = {}; // 遍歷傳入的數組 for (var i=0; arr[i]!=null; i++) { // 這里把數組的值作為對象的key進行判斷,如果不存在則放入 if (!o[arr[i]]) { // 這步是取過濾后的每一項放入結果數組 res.push(arr[i]); // 這步把傳入值作為對象key,并且賦值 o[arr[i]] = true; } } return res; // 返回結果數組, } alert(unique(["帥狐","帥狐",9,4,9,4,"帥","帥"])); // 帥狐,9,4,帥
這樣就完成了數組去重,下一步,按照倒數第二個字母排序:
var arr =["javaScript","java","mongo","mysql", "css","html","nodejs","php"]; function compare(pre,cur){ var p = pre.charAt(pre.length-2); // 取倒數第二個字母 var c = cur.charAt(cur.length-2); if(p < c){ return -1; }else if(p > c){ return 1; }else{ return 0; } } alert(arr.sort(compare)); // 返回["mongo", "php", "nodejs", "html", "javaScript", "mysql", "css", "java"]
之所以多帶帶寫第二步,因為sort()排序是按照字符編碼的順序進行排序,在傳入數值的時候是有陷阱的,不會對數值大小進行排序,看例子:
var arr =[1,10,2,99,3,200]; function sortNum(a,b){ return a - b } alert(arr.sort()); // 返回[1, 10, 2, 200, 3, 99] alert(arr.sort(sortNum)); // 返回[1, 2, 3, 10, 99, 200]
這一回,主要過了一下Function類型,聊了一些函數的技巧,做了兩道題,難度適中。
下一回,咱主要聊一聊,類的模擬,原型,繼承,包括淺聊一下工廠模式,繼續裝逼繼續飛。
話說最近港囧和夏洛特煩惱惹火了很多老歌,對于喜歡聽老歌的我真的是大愛吖,dilililidilililidada...dilililidilililidada...
注:此系飛狐原創,轉載請注明出處
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86118.html
本回內容介紹 上一回聊到JS中模擬接口,裝飾者模式,摻元類,分析了backbone的繼承源碼,感覺還好吧! 介一回,偶們來聊一下在JS單例模式(singleton),單例模式其實運用很廣泛,比如:jquery,AngularJS,underscore吖蝦米的都是單例模式,來吧,直接開始咯: 1. 單例模式 保證一個類只有一個實例,從全局命名空間里提供一個唯一的訪問點來訪問該對象。其實之前寫過的對象...
摘要:本回內容介紹上一回聊到數據類型,簡單的過了一遍,包括個數組新特性等,這一回來聊聊對象,結合數組來實戰一些例子,在做題中成長,記憶會更深刻,來吧,開始咯創建實例的方式有兩種使用操作符后跟構造函數飛狐使用對象字面量表示法飛狐也可以飛狐這種寫法與 本回內容介紹 上一回聊到JS數據類型,簡單的過了一遍,包括9個數組新特性等,這一回來聊聊Object對象,結合數組來實戰一些例子,在做題中成長,記...
摘要:橋接模式之特權函數特權函數,用一些具有特權的方法作為橋梁以便訪問私有空間,可以回憶一下之前的系列。連續自然數分組,計算最多組的個數將至這個連續自然數分成組使每組相加的值相等。個數組中數字最多的一組有個此時的和為。 本回內容介紹 上一回,聊了適配器模式,圖片預加載,介一回,聊橋接模式(Bridge),跟之前一樣,難度比較小,橋接模式將抽象部分與它的實現部分分離,通過橋接模式聯系彼此,同時...
摘要:本回內容介紹上一回,聊了代理模式,虛擬代理,圖片懶加載,介一回,也比較容易,適配器模式,用一個新的接口對現有類的接口進行包裝,處理類與的不匹配。這一回,主要聊了適配器模式,圖片預加載,主要還是理解下一回,聊一聊橋接模式,順便做一做計算題。 本回內容介紹 上一回,聊了代理模式,虛擬代理,圖片懶加載,介一回,也比較容易,適配器模式(Adapter),用一個新的接口對現有類的接口進行包裝,處...
摘要:本回內容介紹上一回,聊了聊狀態模式,并介紹了一下介一回,聊鏈式編程,模擬一下,再模擬一下封裝一個庫。這一回,主要聊了鏈式調用,模擬了,尤其是,希望大家能喜歡這次代碼分享。下一回,聊一聊的策略模式。 本回內容介紹 上一回,聊了聊狀態模式(State),并介紹了一下vue.js;介一回,聊鏈式編程,模擬一下jQuery,再模擬一下underscore.js,封裝一個庫。 1. 鏈式調用 (...
閱讀 3026·2021-11-24 09:39
閱讀 2255·2021-10-08 10:05
閱讀 2749·2021-09-24 13:52
閱讀 1569·2021-09-22 15:07
閱讀 589·2019-08-30 15:55
閱讀 1808·2019-08-30 15:53
閱讀 687·2019-08-30 15:44
閱讀 3116·2019-08-30 11:20