1. JS函數(shù)是一等公民(非常重要)
-
在js中妇多,函數(shù)是非常重要的,并且是一等公民
- 那么意味著函數(shù)的使用是非常靈活的敲街。
- 函數(shù)可以作為另一個(gè)函數(shù)的參數(shù)扫腺,也可以作為另一個(gè)函數(shù)的返回值
自己編寫高階函數(shù)
使用內(nèi)置的高階函數(shù)
1.1 高階函數(shù)
如果一個(gè)函數(shù)接收另一個(gè)函數(shù)作為參數(shù)時(shí),或這個(gè)函數(shù)返回另一個(gè)函數(shù)作為返回值的函數(shù) 稱之為高階函數(shù)
1.1.1 函數(shù)作為參數(shù)使用
function calc(num1,num2,calcFn){
console.log(calcFn(num1,num2));
}
function add(num1,num2){
return num1+num2;
}
function sub(num1,num2){
return num1-num2
}
function mul(num1,num2){
return num1*num2;
}
var m=20;
var n=30;
calc(m,n,add)
calc(m,n,sub)
calc(m,n,mul)
1.1.2 函數(shù)作為返回值使用
function makeAdder(count){
return function add(num){
return count+num;
}
}
var add5=makeAdder(5);
var add10=makeAdder(10);
console.log(add5(10));
console.log(add5(50));
console.log(add10(50));
1.2 函數(shù)(function)和方法(method)的區(qū)別
- 函數(shù):當(dāng)一個(gè)function是獨(dú)立的蚕钦,不屬于任何對(duì)象的方法時(shí)亭病,則稱這個(gè)function是函數(shù)
- 方法:如果一個(gè)function不是獨(dú)立的,是屬于某個(gè)對(duì)象嘶居,則這個(gè)function是方法
1.2.1 函數(shù)
function foo(){ //foo是一個(gè)函數(shù)
}
1.2.2 方法
var obj={
foo:function(){ //這個(gè)foo函數(shù)是obj的一個(gè)方法
}
}
1.3 數(shù)組一些方法的使用
var nums=[10,5,11,100,55]
// 函數(shù)function:獨(dú)立的function罪帖,稱之為是函數(shù)
// methods:方法:當(dāng)某個(gè)function屬于某個(gè)對(duì)象時(shí),我們稱這個(gè)函數(shù)是這個(gè)對(duì)象的方法
/**
* * filter
* nums.filter((item,index,arr)=>boolean) //這個(gè)回調(diào)函數(shù)會(huì)回調(diào)5次邮屁,因?yàn)橛?個(gè)元素
* item:值 index:下標(biāo) arr:當(dāng)前這個(gè)數(shù)組的引用
*/
// * 過濾 返回一個(gè)新的數(shù)組
var newNums= nums.filter(function(item){
return item%2===0
})
console.log(newNums);
// * map 映射 [10,5,11,100,55] 返回一個(gè)新的數(shù)組
var mapNums=nums.map(function(item){
return item*10
})
console.log(mapNums); //[ 100, 50, 110, 1000, 550 ]
// * forEach 遍歷 沒有返回值
nums.forEach(function(item){
console.log(item);
})
// * find(返回?cái)?shù)組中元素) findIndex(返回在數(shù)組中的索引)
// let a=nums.find(function(item){
// return item===11
// })
// console.log("a:",a);
var friends=[
{name:"why",age:18},
{name:"wjy",age:20},
{name:"hyz",age:22},
{name:"tt",age:18},
]
var item=friends.find(function(item){
return item.name=='wjy'
})
console.log(item); //{ name: 'wjy', age: 20 }
var index=friends.findIndex(function(item){
return item.name=='hyz'
})
console.log("index:",index); //index: 2
// * reduce 可以對(duì)原來的數(shù)組進(jìn)行統(tǒng)計(jì)或者累加 nums:[10,5,11,100,55]
// * reduce函數(shù)有兩個(gè)參數(shù)整袁,第一個(gè)參數(shù)是回調(diào)函數(shù),第二個(gè)參數(shù)是回調(diào)函數(shù)的第一個(gè)參數(shù)的初始值
// * 回調(diào)函數(shù)的參數(shù)preValue:是上一次回調(diào)函返回的值
var total=nums.reduce(function(preValue,item){
return preValue+item
},0)
console.log(total); //181
2. JS中閉包的定義
閉包的定義佑吝,分成兩個(gè):在計(jì)算機(jī)科學(xué)中和在JavaScript中
-
在計(jì)算機(jī)科學(xué)對(duì)閉包的定義:(維基百科)
- 閉包(英語(yǔ):closure) 又稱詞法閉包(lexical closure)或函數(shù)閉包
- 是支持在頭等函數(shù)的編程語(yǔ)言中坐昙,實(shí)現(xiàn)詞法綁定的一種技術(shù)
- 閉包在實(shí)現(xiàn)上是一個(gè)結(jié)構(gòu)體,它存儲(chǔ)了一個(gè)函數(shù)和一個(gè)關(guān)聯(lián)的環(huán)境(相當(dāng)于一個(gè)符號(hào)查找表)
- 閉包和函數(shù)最大的區(qū)別在于芋忿,當(dāng)捕捉閉包的時(shí)候炸客,它的自由變量會(huì)在捕捉時(shí)被確定,這樣即使脫離了捕捉時(shí)的上下文戈钢,它也能照常運(yùn)行痹仙。
-
閉包的概念出現(xiàn)于60年代,最早實(shí)現(xiàn)閉包的程序是Scheme殉了,那么我們就可以理解為什么JavaScript中有閉包
- 因?yàn)閖s的大量設(shè)計(jì)是來源于Scheme的
- 一個(gè)函數(shù)和對(duì)其周圍狀態(tài)(Lexical Enviroment 詞法環(huán)境)的引用捆綁在一起(或者說函數(shù)被引用包圍)开仰,這樣的組合就是閉包(closure)
- 也就是說,閉包你可以在一個(gè)內(nèi)層函數(shù)中訪問到其外層函數(shù)的作用域
- 在js中薪铜,每當(dāng)創(chuàng)建一個(gè)函數(shù)众弓,閉包就會(huì)在函數(shù)創(chuàng)建的同時(shí)被創(chuàng)建出來
-
codewhy老師的總結(jié)
- 一個(gè)普通的函數(shù)function,如果它可以訪問外層作用域的變量痕囱,那么它就是閉包
- 從廣義上來講田轧,javascript函數(shù)都是閉包
- 從狹義上來講暴匠,javascript中的一個(gè)函數(shù)鞍恢,如果訪問了外層作用域的變量,那么它就是一個(gè)閉包每窖。
- 一個(gè)普通的函數(shù)function,如果它可以訪問外層作用域的變量痕囱,那么它就是閉包
2.1 代碼示例解析
function foo(){
var name="foo";
function bar(){
console.log(name);
}
return bar;
}
var fn=foo();
fn()
// 閉包包括兩個(gè)部分: 函數(shù)+可訪問的自由變量
16.png
- 在這里原本應(yīng)該銷毀的foo的AO對(duì)象帮掉,但是因?yàn)閎ar函數(shù)在引用其name,所以并沒有銷毀
3. 閉包的內(nèi)存泄漏
本來該被銷毀的對(duì)象窒典,卻一直沒有被銷毀蟆炊,會(huì)造成內(nèi)存泄漏。
- 從根對(duì)象開始瀑志,能夠被訪問的對(duì)象不會(huì)被銷毀
function foo(){
var name="foo";
var age=18;
function bar(){
console.log(name);
}
return bar;
}
let fn=foo()
fn()
17.png
- 例如上面的AO(0X1002)涩搓,一直未被銷毀污秆,但其實(shí)bar()函數(shù)只執(zhí)行了一次,應(yīng)當(dāng)被銷毀
18.png
- 因?yàn)楦鶎?duì)象可到達(dá)bar昧甘、bar又可到達(dá)foo的AO
- 因?yàn)镚C采用的是清除標(biāo)記良拼,只要能從根對(duì)象可到達(dá)的所有對(duì)象不會(huì)被銷毀,不可到達(dá)的對(duì)象會(huì)被銷毀
那怎么解決以上的內(nèi)存泄漏呢充边?
其實(shí)只要fn調(diào)用完后庸推,并設(shè)置為null,這樣從根對(duì)象就不可到達(dá)bar了浇冰,所以最后bar和foo的AO都被銷毀了
4.AO不使用的屬性
我們來探究一個(gè)問題贬媒,就是AO不會(huì)被銷毀時(shí),是否里面的所有屬性都不會(huì)被銷毀肘习?
下面這段代碼中name屬于閉包的父級(jí)作用域中的變量:
我們知道形成閉包之后age一定不會(huì)被銷毀际乘,那么name是否被銷毀呢?
- 這里我使用了斷點(diǎn)漂佩,我們可以在瀏覽器上查看結(jié)果:
19.png
5.總結(jié)
閉包.png