Js閉包

Snipaste_20200510_172501.jpg

先了解變量提升與函數(shù)提升

  1. 變量聲明提升
    通過var聲明的變量,在定義語句之前就能訪問到
    值:undefined
  2. 函數(shù)提升聲明
    通過function聲明的函數(shù),在函數(shù)之前就能直接調用
    值:函數(shù)對象
var a=3
function fn(){
  console.log(a)
  var a=4
}
fn()  //a輸出多少撞反? undefined

console.log(b) //undefined 變量提升
fn2() //可調用 函數(shù)提升
fn3() //不可調用 變量提升

var b=3
function fn2(){
    console.log("fn2()")
}

var fn3=function(){
  console.log("fn3()")
}

再了解執(zhí)行上下文

  1. 代碼分類(位置)
    全局代碼
    函數(shù)(局部)代碼
  2. 全局執(zhí)行上下文
    在執(zhí)行全局代碼前將window確定為全局執(zhí)行上下文
    對全局數(shù)據(jù)進行預處理
    *var定義的全局變量==>undefined,添加為window的屬性
    *function聲明的全局變量==>賦值(fun),添加為window的方法
    *this ==>賦值(window)
    開始執(zhí)行全局代碼
  3. 函數(shù)執(zhí)行上下文
    在調用函數(shù)磨确,準備執(zhí)行函數(shù)體之前,創(chuàng)建對應的函數(shù)執(zhí)行上下文對象
    對局部數(shù)據(jù)進行預處理
    *形參變量==>賦值(實參)==>添加為執(zhí)行上下文屬性
    *arguments==>賦值(實參列表)沥潭,添加為執(zhí)行上下文屬性
    *var定義的局部變量==>undefined,添加為執(zhí)行上下文的屬性
    *function聲明的函數(shù)==>賦值(fun),添加為執(zhí)行上下文的方法
    *this==>賦值(調用函數(shù)的對象)
    開始執(zhí)行函數(shù)體代碼
//放到html 的script中運行
//全局執(zhí)行上下文
console.log(a1,window.a1)
a2()
console.log(this)

var a1 = 3
function a2(){
  console.log("a2()")
}
console.log(a1)

//函數(shù)執(zhí)行上下文
function fn(a1){
  console.log(a1) //2
  console.log(a2) //undefined
  a3() //a3()
  console.log(this)  //window
  console.log(arguments) //(2,3)

  var a2 = 3
  function a3(){
    console.log("a3()")
  }
}
fn(2,3)

再了解下作用與作用于

var x= 10;
function fn(){
console.log(x);
}
function show(f){
  var x=20
  fn();
}
show(fn)

閉包

  1. 當一個嵌套的內部(子)函數(shù)引用了嵌套的外部(父)函數(shù)的變量(函數(shù))時政敢,就產(chǎn)生了閉包
  2. 閉包包含被引用變量(函數(shù))的對象

最簡單的閉包

function fn1(){
  var a=2
  function fn2(){//執(zhí)行函數(shù)定義就會產(chǎn)生閉包(不用調用內部函數(shù))
    console.log(a)
  }
  // fn2()
}
fn1()

常見的閉包
將函數(shù)作為另一個函數(shù)的返回值


function fn1(){
  //此時閉包已經(jīng)產(chǎn)生(函數(shù)提升其徙,內部函數(shù)對象已創(chuàng)建)
  var a=2
  function fn2(){
    a++
    console.log(a)
  }
  return fn2()
}
var f=fn1()
f() //3
f() //4
f=null //閉包死亡 (包含閉包的函數(shù)對象成為垃圾對象)

*將函數(shù)實參傳給另一個函數(shù)調用
function showDelay(msg,time){
setTimeout(function(){
alert(msg) //假如沒有alert(msg) 就不會產(chǎn)生閉包
},time)
}
showDelay("111",1000)

作用:

  1. 使用函數(shù)內部的變量在函數(shù)執(zhí)行完后,仍然存活在內存中(延長了局部變量的生命周期)
  2. 讓函數(shù)外部可以操作(讀寫)到函數(shù)內部的數(shù)據(jù)(變量/函數(shù))

生命周期:

  1. 產(chǎn)生:嵌套內部函數(shù)定義就會產(chǎn)生閉包(不用調用內部函數(shù))
  2. 死亡:嵌套內部函數(shù)成為垃圾對象

缺點:

  1. 延長了局部變量的生命周期喷户,占用時間變長唾那,容易造成內存泄漏 記得釋放f=null

鞏固:

var name = "window"
var object = {
  name: "obj",
  getNameFunc: function () {
    return function () {
      return this.name;
    }
  }

}
console.log(object.getNameFunc()())  

var name2 = "window"
var object2 = {
  name: "obj",
  getNameFunc: function () {
    var that = this
    return function () {
      return this.name;
    }
  }

}
console.log(object2.getNameFunc()())

function fun(n, o) {
  console.log(o)
  return {
    fun: function (m) {
      return fun(m, n)
    }
  }
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3) //undefined 0 0 0
var b = fun(0).fun(1).fun(2).fun(3)//undefined 0 1 2
var c = fun(0).fun(1); c.fun(2); c.fun(3) //undefined 0 1 1

這個東西當年做對的,現(xiàn)在回頭反而不會了褪尝。闹获。。河哑。
關鍵點:
a.fun(1)并沒有一個新的變量接受避诽,所以閉包是產(chǎn)生了但是立即消失了
var a1=fun(0); var a2=a1.fun(1);var a3=a2.fun(2) ;var a4=a3.fun(2) 可以參照這條理解。

運用:
節(jié)流與防抖

//<body>
//<button id="btn1">節(jié)流函數(shù)</button>
//<button id="btn2">防抖函數(shù)</button>
//<script type="text/javascript">
function debounce(fn, delay) {
  let timeoutId = null
  console.log("debounce已被運行")
  return function () {
    //console.log("this:",this,'arguments:',arguments)
    const that = this
    const args = arguments
    if (timeoutId) {
      //console.log('刪除定時器')
      clearTimeout(timeoutId)
    }
    timeoutId = setTimeout(() => { console.log('運行需要運行的函數(shù)'); fn.apply(that, args) }, delay)
  }
}

btn1 = document.getElementById('btn1')
btn1.addEventListener('click', throttle(onclick1, 1000), false);
btn2 = document.getElementById('btn2')
btn2.addEventListener('click', debounce(onclick1, 1000), false);
//</script>
//</body>
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末璃谨,一起剝皮案震驚了整個濱河市沙庐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖轨功,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異容达,居然都是意外死亡古涧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門花盐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羡滑,“玉大人,你說我怎么就攤上這事算芯∑饣瑁” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵熙揍,是天一觀的道長职祷。 經(jīng)常有香客問我,道長届囚,這世上最難降的妖魔是什么有梆? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮意系,結果婚禮上泥耀,老公的妹妹穿的比我還像新娘。我一直安慰自己蛔添,他們只是感情好痰催,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迎瞧,像睡著了一般夸溶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凶硅,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天蜘醋,我揣著相機與錄音,去河邊找鬼咏尝。 笑死压语,一個胖子當著我的面吹牛,可吹牛的內容都是我干的编检。 我是一名探鬼主播胎食,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼允懂!你這毒婦竟也來了厕怜?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粥航,沒想到半個月后琅捏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡递雀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年欺缘,在試婚紗的時候發(fā)現(xiàn)自己被綠了秆乳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陈哑。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡合瓢,死狀恐怖,靈堂內的尸體忽然破棺而出杨凑,到底是詐尸還是另有隱情滤奈,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布撩满,位于F島的核電站蜒程,受9級特大地震影響,放射性物質發(fā)生泄漏伺帘。R本人自食惡果不足惜搞糕,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望曼追。 院中可真熱鬧窍仰,春花似錦、人聲如沸礼殊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晶伦。三九已至碟狞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間婚陪,已是汗流浹背族沃。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泌参,地道東北人脆淹。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像沽一,于是被迫代替她去往敵國和親盖溺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354