函數(shù)進(jìn)階
定義函數(shù)的方式
- 聲明函數(shù)
function xxx(){}
這種方式是最直接的聲明方式晴股,js執(zhí)行時(shí)這種方式會(huì)被預(yù)解析(聲明提升) - 函數(shù)表達(dá)式
var fn = function() {};
這種方法是通過賦值位他,將函數(shù)賦值給變量,預(yù)解析只有變量和函數(shù)本身枚钓,賦值操作不會(huì),所以這種方式函數(shù)不會(huì)被預(yù)解析 - 構(gòu)造函數(shù)方式
var fn = new Function('參數(shù)'瑟押,'參數(shù)'搀捷,'內(nèi)部代碼');
這種定義方式不會(huì)用,執(zhí)行速度慢多望,只做了解 - 另外在新版瀏覽器中嫩舟,
if
語句中的函數(shù)聲明不會(huì)被預(yù)解析,但老版瀏覽器又會(huì)怀偷。所以如果想通過判斷條件來聲明函數(shù)家厌,又要顧及兼容性,可以用表達(dá)式的方式
偽變量this
-
this
是函數(shù)內(nèi)部的偽變量椎工,用于指向調(diào)用者饭于。關(guān)于它的指向其實(shí)完全不會(huì)混淆,誰調(diào)用了該函數(shù)晋渺,那么this
就指向誰镰绎,記住這一點(diǎn)就行
函數(shù)對(duì)象的成員進(jìn)階
- 前面已經(jīng)說過了函數(shù)就是一個(gè)對(duì)象,它有默認(rèn)的屬性和方法木西。下面說下call畴栖、apply、bind的進(jìn)階用法
-
.call(改變指向?qū)ο蟀饲В椒▽?duì)應(yīng)參數(shù))
這個(gè)方法的作用是調(diào)用函數(shù)吗讶,并修改函數(shù)內(nèi)部this的指向- 進(jìn)階用法舉例:比如一個(gè)偽數(shù)組(數(shù)組的形式燎猛,但沒有通過Array構(gòu)造函數(shù)創(chuàng)建,所有不能使用原型對(duì)象中的默認(rèn)方法)照皆。如果我們想要讓這個(gè)偽數(shù)組也使用數(shù)組的方法重绷,那么可以
Array.prototype.push.call(偽數(shù)組);
,這樣實(shí)際上是讓構(gòu)造函數(shù)調(diào)用方法膜毁,但是通過call來改變指向昭卓,達(dá)到目的。這只是一個(gè)用法瘟滨,不是唯一
- 進(jìn)階用法舉例:比如一個(gè)偽數(shù)組(數(shù)組的形式燎猛,但沒有通過Array構(gòu)造函數(shù)創(chuàng)建,所有不能使用原型對(duì)象中的默認(rèn)方法)照皆。如果我們想要讓這個(gè)偽數(shù)組也使用數(shù)組的方法重绷,那么可以
-
.apply(改變指向?qū)ο?數(shù)組)
這個(gè)方法的作用是調(diào)用函數(shù)候醒,并修改函數(shù)內(nèi)部this的指向,并且參數(shù)是數(shù)組的形式傳入杂瘸,它會(huì)在自動(dòng)拆分?jǐn)?shù)組將值依次傳入- 進(jìn)階用法舉例:
Math.max()
這個(gè)方法可以返回一組數(shù)字中的最大值倒淫,但是它的參數(shù)只能是一組數(shù)字,不能是數(shù)組败玉。這個(gè)時(shí)候就可以Math.max.apply(Math, 數(shù)組)
敌土,通過apply
方法自動(dòng)拆分?jǐn)?shù)組后,就能直接實(shí)現(xiàn)了运翼。注意這里第一個(gè)參數(shù)因?yàn)椴簧婕案淖冎赶蚍蹈桑詡魉旧碚{(diào)用者即可
- 進(jìn)階用法舉例:
-
.bind(改變指向?qū)ο螅椒▽?duì)應(yīng)參數(shù))
這個(gè)方法的作用是修改函數(shù)內(nèi)部this的指向南蹂,并返回一個(gè)新的函數(shù)犬金,不會(huì)直接調(diào)用- 進(jìn)階用法:它主要的應(yīng)用場(chǎng)景是在函數(shù)不需要立刻調(diào)用的時(shí)候念恍。比如函數(shù)作為一個(gè)參數(shù)六剥,或者作為一個(gè)賦值對(duì)象時(shí)。當(dāng)時(shí)并不需要立即執(zhí)行函數(shù)峰伙,就可以用它
-
aguments
函數(shù)中默認(rèn)有這個(gè)變量疗疟,也有這個(gè)屬性(不是同一個(gè)),但是作用都是相同瞳氓。用來記錄傳入的實(shí)參策彤,它本身是一個(gè)偽數(shù)組。在不確定傳入實(shí)參的情況下匣摘,可以用它直接獲取到店诗,較常用需要掌握 -
caller
屬性記錄該函數(shù)的調(diào)用者 -
name
屬性記錄函數(shù)名 -
length
屬性記錄形參個(gè)數(shù)
高階函數(shù)
- 當(dāng)一個(gè)函數(shù)作為參數(shù)或者作為返回值的是,它就是高階函數(shù)
- 函數(shù)作為參數(shù)可以通過sort方法的參數(shù)(函數(shù))調(diào)整排序方式來理解
- 把函數(shù)作為返回值也是很常用的音榜。舉例:很多場(chǎng)景下庞瘸,我們需要一個(gè)函數(shù)來接受參數(shù),但是因?yàn)閰?shù)的動(dòng)態(tài)變化赠叼,如果只有一個(gè)函數(shù)擦囊,那么參數(shù)會(huì)被定死违霞。所以我們可以返回一個(gè)函數(shù),讓返回的函數(shù)再接收值并執(zhí)行邏輯瞬场,這樣就是可以讓參數(shù)動(dòng)態(tài)變化
- 具體可以看案例代碼理解
閉包
- 閉包是一個(gè)很抽象的概念买鸽,準(zhǔn)確來說它是一種程序現(xiàn)象也是一種組合環(huán)境。在js中創(chuàng)建函數(shù)時(shí)贯被,會(huì)自動(dòng)生成一個(gè)作用域環(huán)境眼五。其他部分語言中該作用域中的局部變量或函數(shù)會(huì)隨著作用域執(zhí)行完后銷毀而變得不可訪問,但在js中卻不是這樣
- 哪怕作用域銷毀彤灶,但是只要其他作用域訪問其中局部變量或函數(shù)(內(nèi)部函數(shù)或者本身)弹砚,依然能夠訪問到
- 所以閉包也能理解了,它是由函數(shù)和創(chuàng)建該函數(shù)的詞法環(huán)境組合而成枢希,它包含了該函數(shù)中所有能訪問的局部變量或函數(shù)(內(nèi)部函數(shù)或者本身)桌吃,讓它們?cè)诤瘮?shù)執(zhí)行完銷毀后仍然可以被訪問
- 閉包的作用,簡(jiǎn)單來說就是延展作用域苞轿,在某些情景下可以讓功能實(shí)現(xiàn)更方便茅诱。但不是所有場(chǎng)景都一定要用閉包
定時(shí)器工作原理
- js代碼在執(zhí)行時(shí),是從上往下執(zhí)行的搬卒。這是因?yàn)閳?zhí)行是瑟俭,會(huì)把所有代碼放到執(zhí)行棧當(dāng)中。但是定時(shí)器的參數(shù)函數(shù)并不會(huì)在執(zhí)行棧中處理契邀,而是把函數(shù)放到任務(wù)隊(duì)里中進(jìn)行排隊(duì)摆寄。當(dāng)執(zhí)行棧中的代碼執(zhí)行完畢后,根據(jù)消息循環(huán)(就是觸發(fā)條件)坯门,執(zhí)行任務(wù)隊(duì)列中對(duì)應(yīng)的函數(shù)
- 不光是定時(shí)器微饥,事件觸發(fā)函數(shù)也是同樣的原理,也會(huì)把函數(shù)放到事件隊(duì)列中古戴。當(dāng)觸發(fā)事件后欠橘,會(huì)從事件隊(duì)列中取出對(duì)應(yīng)函數(shù)并執(zhí)行
關(guān)于多次調(diào)用容易發(fā)生的理解誤區(qū)
- 假設(shè)一個(gè)對(duì)象
obj
它有一個(gè)方法fun
,fun
中返回值是一個(gè)函數(shù) - 那么輸出
obj.fun()()
時(shí)现恼,返回函數(shù)中的this
指向的誰呢肃续?答案是window
,而不是obj
- 因?yàn)?code>obj.fun()這段代碼執(zhí)行時(shí)叉袍,this指向的是obj始锚,執(zhí)行完畢后此時(shí)
obj.fun()
就是返回的一個(gè)函數(shù)。再次調(diào)用返回的函數(shù)喳逛,注意返回值函數(shù)是沒有對(duì)象調(diào)用的瞧捌,所以默認(rèn)是由window來調(diào)用的
遞歸
- 遞歸實(shí)際上就是函數(shù)再內(nèi)部不停的調(diào)用自己,在使用遞歸時(shí)一般都會(huì)加上一個(gè)結(jié)束條件艺配,不然遞歸就是一個(gè)死循環(huán)察郁,最終導(dǎo)致內(nèi)存不足報(bào)錯(cuò)
- 具體執(zhí)行過程衍慎,可以通過斷點(diǎn)的方式查看分析
- 遞歸在使用時(shí)沒必要完全想通數(shù)學(xué)邏輯,實(shí)際上只需要明白要實(shí)現(xiàn)的功能該怎么寫皮钠,并套用對(duì)應(yīng)公式即可
對(duì)象拷貝
- 淺拷貝
- 正常情況下如果想要拷貝一個(gè)對(duì)象稳捆,使用
for in
遍歷對(duì)象并依次賦值給新對(duì)象即可 - 但是這樣會(huì)出現(xiàn)一個(gè)問題,如果拷貝的成員中麦轰,有一個(gè)屬性是對(duì)象乔夯。那么實(shí)際上拷貝的是該對(duì)象的引用地址,而不管哪個(gè)對(duì)象修改值款侵,都會(huì)通過引用地址修改對(duì)象成員的值末荐,那么就不是我們想要的結(jié)果了
- 這種拷貝也叫做淺拷貝
- 正常情況下如果想要拷貝一個(gè)對(duì)象稳捆,使用
- 深拷貝
- 深度拷貝就是將對(duì)象成員也進(jìn)行拷貝,而不再是拷貝引用地址新锈,這樣上面的問題也就解決了
- 具體深度拷貝實(shí)現(xiàn)代碼查看案例甲脏,也是遞歸的一種應(yīng)用場(chǎng)景