摘要:問題匿名函數(shù)的執(zhí)行具有全局性,所以閉包函數(shù)的一般指向,因為里面的閉包函數(shù)是在作用域下執(zhí)行的,也就是說,指向可以改寫成如下,內(nèi)存泄漏問題如果閉包在作用域鏈中保存著元素,則該元素內(nèi)存將無法自動銷毀。
介紹你下你理解的閉包?不管怎樣!我最近聽到很多次!感覺是不好好總結(jié)一下沒法面對那些犀利的追問!
如果覺得閉包理解的很透徹,就直接跳到最后看題目!
小紅書的解釋閉包是有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。明白了嗎?就是一個函數(shù),一個可以訪問其他函數(shù)中變量的函數(shù)。所以常見的創(chuàng)建閉包的方式就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。
function bag(num){ return function(){ return num } } var bagc = bag(12) console.log(bagc()) //12
可以看到在bag內(nèi)部的匿名函數(shù)可以訪問外部bag函數(shù)的變量num。
2.閉包的用處閉包可以用在許多地方。它的最大用處有兩個,一個是可以讀取函數(shù)內(nèi)部的變量,另一個就是讓這些變量的值始終保持在內(nèi)存中。
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); //變量n被保存了 result(); // 1000
上面是阮一峰在文檔中的一個例子,讀取函數(shù)內(nèi)部變量我覺得用處一般吧,讓變量保持在內(nèi)存中的用處倒是不少,像經(jīng)常使用的that=this等。下面看一個常見的問題:
for(var i = 0;i <10;i++){ setTimeout(()=>{ console.log(i) },1000) } //上面的代碼我們希望按照索引值打印,結(jié)果卻打印了10個10,為什么就不解釋了,i是全局變量。 //換成下面的寫法,就能解決問題,正是因為閉包 讓變量的值始終保持在內(nèi)存中,每個i都存在了num這個局部變量中 for(var i = 0;i <10;i++){ (function(num){ setTimeout(()=>{ console.log(num) },1000) })(i) }3.使用閉包需要注意的點
閉包雖然在解決一些問題上有好處,但是由此引發(fā)的一些問題要注意,而且由于閉包會攜帶外部函數(shù)作用域,所以內(nèi)存占用比較大,所以盡量少用、慎用閉包。
1.變量問題正是因為閉包可以使用外部變量,所以下面的代碼中,返回的匿名函數(shù)中對變量i的使用將會是最終的值,數(shù)組中存放的函數(shù)的返回值將都會是10。
function test() { var result = []; for(var i = 0; i<10; i++){ result.[i] = function () { return i; } } return result }
需要將上述代碼改寫成如下:
function test() { var result = []; for(var i = 0; i<10; i++){ result.[i] = function (num) { return function() { console.info(num); } }(i) } return result }
此時訪問的num,是上層函數(shù)執(zhí)行環(huán)境的num,數(shù)組有10個函數(shù)對象,每個對象的執(zhí)行環(huán)境下的number都不一樣。
2.this問題匿名函數(shù)的執(zhí)行具有全局性,所以閉包函數(shù)的this一般指向window;
var object = { name: "object", getName:function() { return function() { console.info(this.name) } } } object.getName()() // underfined // 因為里面的閉包函數(shù)是在window作用域下執(zhí)行的,也就是說,this指向windows
可以改寫成如下:
var object = { name: "object", getName:function() { var that = this; return function() { console.info(that.name) } } } object.getName()() // object3.內(nèi)存泄漏問題
如果閉包在作用域鏈中保存著html元素,則該元素內(nèi)存將無法自動銷毀。
function showId() { var el = document.getElementById("app") el.onclick = function(){ aler(el.id) // 這樣會導(dǎo)致閉包引用外層的el,當(dāng)執(zhí)行完showId后,el無法釋放 } } // 改成下面 function showId() { var el = document.getElementById("app") var id = el.id el.onclick = function(){ aler(id) // 這樣會導(dǎo)致閉包引用外層的el,當(dāng)執(zhí)行完showId后,el無法釋放 } el = null // 主動釋放el }4.閉包練習(xí)題
好了,看到這里是不是感覺對閉包理解的很到位了?別著急,看看這兩個小問題測試一下!
1.與函數(shù)調(diào)用結(jié)合var Test = { close:function(val){ return function (z){ return ++ val +z } } } var getClose = function(val){ return Test[val] } var fn = getClose("close") var cover = fn(100) console.log(cover(200)) console.log(cover(300)) console.log(fn(100)(200)) console.log(fn(100)(200)) console.log(getClose("close")(100)(300)) //輸出結(jié)果見結(jié)尾處2.與dom結(jié)合
var container1 = document.getElementById("container1") var container2 = document.getElementById("container2") var container3 = document.getElementById("container3") var container4 = document.getElementById("container4") var container5 = document.getElementById("container5") var innerHTML = "window的html" var events = { innerHTML:"我是events", getHtml:function (){ console.log(this.innerHTML) }, setFun:function(){ return this.getHtml }, proxy:function(){ var self = this; return function(){ self.getHtml() } } } container1.onclick = events.getHtml; container2.onclick = events.setFun(); container3.onclick = events.proxy(); container4.onclick = function(){ window.setTimeout(events.setFun(),0) } container5.onclick = function(){ window.setTimeout(events.proxy(),0) }
還ok?有沒有被繞暈!暈了就打開電腦敲吧
看一下輸出結(jié)果吧 第一題:401 402 301 301 401 第二題:container container2 我是events window的html 我是events
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106511.html
摘要:在的開發(fā)者工具中,通過斷點調(diào)試,我們能夠非常方便的一步一步的觀察的執(zhí)行過程,直觀感知函數(shù)調(diào)用棧,作用域鏈,變量對象,閉包,等關(guān)鍵信息的變化。其中表示當(dāng)前的局部變量對象,表示當(dāng)前作用域鏈中的閉包。 showImg(https://segmentfault.com/img/remote/1460000008404321); 在前端開發(fā)中,有一個非常重要的技能,叫做斷點調(diào)試。 在chrome...
摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強大而且簡單的方式。插....
摘要:他的組成如下對的就是你關(guān)注的那個變量對象作用域鏈跟閉包相關(guān)由于是單線程的,一次只能發(fā)生一件事情,其他事情會放在指定上下文棧中排隊。 閉包和this,是兩個相當(dāng)高頻的考點,然而你有沒有想過,實際上他們兩個都跟同一個知識點相關(guān)? 有請我們的這篇文章的主角,執(zhí)行上下文 執(zhí)行上下文 執(zhí)行上下文是什么 可以簡單理解執(zhí)行上下文是js代碼執(zhí)行的環(huán)境,當(dāng)js執(zhí)行一段可執(zhí)行代碼時,會創(chuàng)建對應(yīng)的執(zhí)行上下文...
摘要:然而,異步函數(shù)不會立即被推入調(diào)用堆棧,而是會被推入任務(wù)隊列,并在調(diào)用堆棧為空后執(zhí)行。將事件從任務(wù)隊列傳輸?shù)秸{(diào)用堆棧稱為事件循環(huán)。我們調(diào)用接受和或返回另一個函數(shù)稱為高階函數(shù)的函數(shù)。 為了保證可讀性,本文采用意譯而非直譯 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 1.如何理解 JS 中的this關(guān)鍵字? JS 初學(xué)者總是對 this 關(guān)鍵字感到困惑,因為與其他現(xiàn)...
閱讀 1262·2023-04-26 02:38
閱讀 946·2023-04-25 20:13
閱讀 3600·2021-11-19 11:31
閱讀 2405·2019-08-30 15:55
閱讀 2732·2019-08-30 14:11
閱讀 3173·2019-08-30 13:45
閱讀 1385·2019-08-29 18:41
閱讀 1158·2019-08-29 16:18