一、閉包
一句話概括專有名詞
閉包函數(shù):聲明在一個(gè)函數(shù)中的函數(shù)叫做閉包函數(shù)晌块。
閉包:內(nèi)部函數(shù)總是可以訪問(wèn)其所在的外部函數(shù)中聲明的參數(shù)或變量爱沟。
閉包的幾個(gè)特點(diǎn)
- 函數(shù)嵌套函數(shù)
- 內(nèi)部函數(shù)可以引用外部函數(shù)的參數(shù)和變量
- 外部函數(shù)的變量會(huì)常駐內(nèi)存中不銷毀
例子
function external(){
var i = 0;
function inside(){
i++;
console.log(i);
}
return inside;
}
var run = external();
run();
run();
run();
var run2 = external();
run2();
run2();
run2();
執(zhí)行結(jié)果:1 2 3 1 2 3
閉包的應(yīng)用場(chǎng)景
function Person(value){
var name = value;
this.getName = function(){
return name;
}
this.setName = function(value){
name = value;
}
}
var person = new Person('張三');
console.log(person.getName()); // 張三
person.setName('李四');
console.log(person.getName()); // 李四
以上代碼的構(gòu)造函數(shù)中定義了兩個(gè)特權(quán)方法 getName()
setName()
這兩個(gè)方法可以通過(guò)對(duì)象訪問(wèn),而且都有權(quán)訪問(wèn)私有變量 name
但是在 Person
外部是無(wú)法訪問(wèn)到 name
的
二匆背、堆棧
棧內(nèi)存主要用于存儲(chǔ)基本類型的變量呼伸,包括Boolean、Number钝尸、String括享、undefined、null以及對(duì)象變量的指針
堆內(nèi)存主要用于存儲(chǔ)對(duì)象(引用類型值 Object Function)
全局對(duì)象(GO)
var globalObject = {
Math: {},
String: {},
document: {}
...
window: this
}
執(zhí)行上下文棧(ECStack)
執(zhí)行上下文(EC)
. 值存儲(chǔ)區(qū)(變量對(duì)象VO)
. 活動(dòng)對(duì)象(AO)
Scope:作用域珍促,創(chuàng)建函數(shù)的時(shí)候賦值
Scope Chain:作用域鏈
全局執(zhí)行上下文
- 在執(zhí)行全局代碼前將window確定為全局執(zhí)行上下文
- 對(duì)全局?jǐn)?shù)據(jù)進(jìn)行預(yù)處理
var定義的全局變量賦值為undefined奶浦,添加為window的屬性
function聲明的全局函數(shù)賦值fun,添加為window的方法
this賦值window - 開(kāi)始執(zhí)行全局代碼
函數(shù)執(zhí)行上下文
- 在調(diào)用函數(shù)踢星,準(zhǔn)備執(zhí)行函數(shù)體之前澳叉,創(chuàng)建對(duì)應(yīng)的函數(shù)執(zhí)行上下文對(duì)象
- 對(duì)局部數(shù)據(jù)進(jìn)行預(yù)處理
形參變量賦值實(shí)參,添加為執(zhí)行上下文的屬性
arguments賦值實(shí)參列表沐悦,添加為執(zhí)行上下文的屬性
var定義的局部變量賦值undefined成洗,添加為執(zhí)行上下文的屬性
function聲明的函數(shù)賦值fun,添加為執(zhí)行上下文的方法
this賦值調(diào)用函數(shù)的對(duì)象 - 開(kāi)始執(zhí)行函數(shù)體代碼
1藏否、var 和function聲明創(chuàng)建在全局對(duì)象中瓶殃,而let const class聲明的變量創(chuàng)建在全局scope中
2、先到全局scope中找變量副签,查找不到再到全局對(duì)象中查找
三遥椿、深淺克隆
淺克隆只是克隆了內(nèi)存地址,實(shí)際操作的還是同一塊內(nèi)存空間淆储,所以在克隆后改變值會(huì)影響到被克隆原有的值冠场。
案例
let a = {b: 1}
let c = a
c.b = 3
console.log(a) // {b: 3}
那如何才能使變量c新開(kāi)辟一塊兒空間不和a公用呢,這個(gè)時(shí)候就要用深克隆的方式了
let a = {b: 1}
let c = {...a}
c.b = 3
console.log(a) // {b: 1}
console.log(c) // {b: 3}
但要注意本砰,上面這只是簡(jiǎn)單的一層對(duì)象的深克隆碴裙,如果我寫成多層對(duì)象,深克隆就失效了。
let a = {b: {c: 1}}
let d = {...a}
d.b.c = 3
console.log(a) // {b: {c: 3}}
那像這種該如何深克隆呢舔株,也有辦法莺琳,先把對(duì)象轉(zhuǎn)換成字符串,然后再轉(zhuǎn)換成對(duì)象载慈。
let a = {b: {c: 1}}
let d = JSON.parse(JSON.stringify(a))
d.b.c = 3
console.log(a) // {b: {c: 1}}
console.log(d) // {b: {c: 3}}
但是這里要注意惭等,JSON.stringify是無(wú)法將function,Data等類型轉(zhuǎn)換成字符串的办铡,如果對(duì)象中包含了這樣的類型值咕缎,JSON.stringify會(huì)過(guò)濾掉這些屬性。要想實(shí)現(xiàn)對(duì)含有特殊類型值的對(duì)象實(shí)現(xiàn)深拷貝料扰,就得使用遞歸凭豪。
function deepClone(obj){
// 過(guò)濾特殊情況
if (obj === null) return null;
if (typeof obj !== 'object') return obj;
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (obj instanceof Function) return new Function(obj);
// 不直接創(chuàng)建空對(duì)象的目的是克隆的結(jié)果和之前保持相同的所屬類
let newObj = new obj.constructor;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
let a = {b: {c: 1},d: function(){}}
let e = deepClone(a)
e.b.c = 3
console.log(a) // {b: {c: 1},d: f()}
console.log(e) // {b: {c: 3},d: f()}