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