摘要:前言最近在學前幾天看到兩道題剛開始看懵懵懂懂這幾天通過各種查資料慢慢的理解頓悟了對匿名函數(shù)閉包立即執(zhí)行函數(shù)的理解也更深了一點在此分享給大家我的理解與總結(jié)希望能幫助大家理解因為這篇文章是我用心總結(jié)的查閱了很多的資料所以總結(jié)的比較細篇幅較長如果
前言
最近在學JS,前幾天看到兩道題,剛開始看懵懵懂懂,這幾天通過各種查資料,慢慢的理解,頓悟了,對匿名函數(shù),閉包,立即執(zhí)行函數(shù)的理解也更深了一點,在此分享給大家我的理解與總結(jié),希望能幫助大家理解.因為這篇文章是我用心總結(jié)的,查閱了很多的資料,所以總結(jié)的比較細,篇幅較長,如果沒耐心,建議跳出,點個收藏,以后如果要用到,有耐心想看時,方便查閱.另外如果有啥錯誤,還望指正
題目一function fn() { for (var i = 0; i < 2; i++) { var variate = i; setTimeout(function () { console.log("setTimeout執(zhí)行后:" + variate); }, 1000); } console.log(i); } fn();
最后結(jié)果是啥呢?
結(jié)果是,先打印2,再打印2個1
為什么呢?
先來梳理下函數(shù)執(zhí)行過程:
首先for循環(huán)遍歷i,(0,1)的時候分別將遍歷值傳給variate變量,variate變量最后保存的值為1
當i值為2時,指針跳出循環(huán),執(zhí)行到打印i值這步,此時i=2
執(zhí)行函數(shù)fn(),執(zhí)行完畢后,觸發(fā)setTimeout事件,因為循環(huán)2次,而且最后保存在這個作用域中變量的值為1,所以最后輸出2個1
所以最后的打印的值為2,1,1
分析完了,先不急,我們先來了解下setTimeout事件
setTimeout事件setTimeout事件有兩個參數(shù):事件,時間開始執(zhí)行時間
setTimeout事件是異步的
當調(diào)用setTimeout事件時,會把函數(shù)參數(shù),放到事件隊列中。等主程序運行完,再調(diào)用
理解這個后,答案就很容易得出了
題目二function fn() { for (var i = 0; i < 2; i++) { (function () { var variate = i; setTimeout(function () { alert(variate); }, 1000); })(); } console.log(i); console.log(variate); } fn();
先分析下整體結(jié)構(gòu):
函數(shù)體內(nèi)包含一個for循環(huán)體,循環(huán)體內(nèi)又包含一個匿名函數(shù),形成閉包,加上兩個小括號-->(匿名函數(shù))()形成立即執(zhí)行函數(shù)
再思考下函數(shù)執(zhí)行過程
i=0時,進入函數(shù)體內(nèi),因為是立即執(zhí)行,所以i值進入匿名函數(shù),通過作用域鏈,變量variate獲得i值,匿名函數(shù)體內(nèi)的setTimeout中的變量variate獲得i值,第一輪循環(huán)結(jié)束;
i=1時,執(zhí)行與1同樣的過程;
i=2,跳出循環(huán),打印i,variate;
結(jié)果是啥呢?
Excuse me?竟然有錯誤?
好,那就讓我們來解決錯誤,錯誤顯示variate is not defined,原來是這樣,沒定義,那分析一波,為什么會顯示未定義呢?
首先我們看函數(shù)內(nèi)部,內(nèi)部已經(jīng)定義了,所以我們想到作用域的問題
作用域
變量和函數(shù)的訪問區(qū)域,分全局作用域和函數(shù)作用域,在es6中添加let關(guān)鍵字后有了塊級作用域概念.
變量提升: JS在解析代碼前會先將所有函數(shù)體內(nèi)的變量,提升至函數(shù)體頂端,來看個例子
var Gscope = "global"; function t() { var Gscope; console.log("這是全局變量:"+Gscope);//這是全局變量:undefined Lscope = "local"; console.log("這是局部變量"+Lscope);//這是局部變量local } t();
為什么第一個值為undefined?因為函數(shù)體內(nèi)的Gscope變量被提升至函數(shù)體頂端,但是未賦值,so,undefined.
let關(guān)鍵字:let用于聲明變量,但是let聲明的變量只在let所在的代碼塊(塊級作用域)有用,OK,show code
for (let i = 0; i < 2; i++) { let i = "a"; console.log(i);//a a } console.log(i);//i is not defined
作用域鏈
什么是作用域鏈?有什么用途?怎么創(chuàng)建起來的?
先引用一句高級程序設計里的話:
作用域鏈本質(zhì)上是一個指向變量對象的指針列表,它只引用但不實際包含變量對象
我的理解是:
作用域鏈就相當于是溝通執(zhí)行環(huán)境內(nèi)的各個變量與函數(shù)的橋梁,通過作用域鏈,同一執(zhí)行環(huán)境里面的變量和函數(shù)都有權(quán)利訪問對方;
那不同的執(zhí)行環(huán)境間是怎樣的呢?
不同執(zhí)行環(huán)境間的交流還是通過橋梁(作用域鏈),但是現(xiàn)在橋梁變成單行道了,只能允許內(nèi)部環(huán)境訪問外部環(huán)境,但外部環(huán)境不能訪問內(nèi)部環(huán)境.內(nèi)部環(huán)境通過橋梁能夠向上搜索查詢變量和函數(shù),但外部卻不能向下搜索進入另一個執(zhí)行環(huán)境.理解這個后,出現(xiàn)題目二的問題,variate is not defined,就很容易理解了:
因為他們兩個壓根不在同一個執(zhí)行環(huán)境,而且,里面的變量對象通過閉包能夠訪問外部環(huán)境變量,但外部環(huán)境變量無權(quán)訪問內(nèi)部的變量variate.
這時可能又蹦出一個問題了,"橋梁"(執(zhí)行環(huán)境的作用域鏈)怎么搭建起來的呢?
先創(chuàng)建一個預先包含全局變量對象的作用域鏈,保存在內(nèi)部的[scope]屬性中
調(diào)用函數(shù)時,為函數(shù)搭建一個執(zhí)行環(huán)境
復制函數(shù)的[scope]中的對象構(gòu)建起執(zhí)行環(huán)境的作用域鏈
創(chuàng)建活動對象,并將活動對象推入執(zhí)行環(huán)境的前端
分析完后,再重新閱讀下作用域的概念,會發(fā)現(xiàn)很有道理!
閉包首先提出幾個問題:什么是閉包? 為什么要用它?它有啥缺點?怎么創(chuàng)建?
什么是閉包?
閉包是指有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)
先貼上剛剛那一段代碼
function fn() { for (var i = 0; i < 2; i++) { (function () { var variate = i; setTimeout(function () { console.log("setTimeout執(zhí)行后:"+variate); }, 1000); })();//閉包,立即執(zhí)行函數(shù),匿名函數(shù) } console.log(i);//2 console.log(variate);//variate is not defined } fn();
通過定義可以知道,閉包本質(zhì)還是作用域鏈的問題.
那為什么內(nèi)部環(huán)境能訪問外部環(huán)境呢?
那就先探討下,函數(shù)調(diào)用時會發(fā)生什么吧!
先創(chuàng)建執(zhí)行環(huán)境和作用域鏈;
初始化函數(shù)的活動對象(命名參數(shù)值,arguments);
在作用鏈中搜索具有相應名字的變量,實現(xiàn)對變量的讀取和寫入;
調(diào)用執(zhí)行完畢,銷毀局部活動對象,僅保存全局作用域.
所以關(guān)鍵還是內(nèi)部函數(shù)作用域鏈將外部的活動對象添加到自己作用域中了
這個例子中函數(shù)fn()內(nèi)部嵌套了一個匿名函數(shù)形成閉包,內(nèi)部的variate變量變?yōu)樗接谐蓡T變量,所以外部無法訪問,因而會報錯variate is not defined
為什么用閉包?
因為在閉包內(nèi)部保持了對外部活動對象的訪問,但外部的變量卻無法直接訪問內(nèi)部,避免了全局污染;
可以當做私有成員,彌補了因js語法帶來的面向?qū)ο缶幊痰牟蛔?
可以長久的在內(nèi)存中保存一個自己想要保存的變量.
閉包有啥缺點呢?
可能導致內(nèi)存占用過多,因為閉包攜帶了自身的函數(shù)作用域
閉包只能取得外部包含函數(shù)中得最后一個值
怎么創(chuàng)建閉包?
在函數(shù)內(nèi)部嵌套使用函數(shù)
什么是匿名函數(shù)?
顧名思義,就是沒有名字的函數(shù)
如例子中的代碼就是一個匿名函數(shù)
function () { var variate = i; setTimeout(function () { console.log("setTimeout執(zhí)行后:"+variate); }, 1000); }
匿名函數(shù)優(yōu)缺點?
優(yōu)點:可以通過var關(guān)鍵字創(chuàng)建函數(shù)表達式,函數(shù)表達式不會出現(xiàn)變量提升的情況,只有在真正被解釋執(zhí)行的時候才會執(zhí)行到函數(shù)表達式所在的代碼行,有效避免了全局污染;
缺點:匿名函數(shù)綁定的事件不能解綁
立即執(zhí)行函數(shù)什么是立即執(zhí)行函數(shù)?有什么作用?
什么是立即執(zhí)行函數(shù)?
聲明一個匿名函數(shù),并且馬上調(diào)用它{通過加()的形式}
立即執(zhí)行函數(shù)的形式
(匿名函數(shù))();
(function () { var variate = i; setTimeout(function () { console.log("setTimeout執(zhí)行后:"+variate); }, 1000); })()
為什么要用小括號將匿名函數(shù)包裹起來?
為了通過瀏覽器的語法檢查
作用?
創(chuàng)建一個獨立的作用域,避免全局污染
通過兩道題擴展出來知識點,并且總結(jié)出來,現(xiàn)在對知識點的基礎概念,以及一些實現(xiàn)原理有了很清晰的認識,這種感覺很棒
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94539.html
摘要:也就是說,普通情況下,指向調(diào)用函數(shù)時的對象。在全局執(zhí)行時,則是全局對象。故而的方法因為構(gòu)造函數(shù)閉包的關(guān)系,指向了構(gòu)造函數(shù)作用域內(nèi)的。 日常開發(fā)中,我們經(jīng)常用到this。例如用Jquery綁定事件時,this指向觸發(fā)事件的DOM元素;編寫Vue、React組件時,this指向組件本身。對于新手來說,常會用一種意會的感覺去判斷this的指向。以至于當遇到復雜的函數(shù)調(diào)用時,就分不清this的...
摘要:執(zhí)行返回的內(nèi)部函數(shù),依然能訪問變量輸出閉包中的作用域鏈理解作用域鏈對理解閉包也很有幫助。早期的版本里采用是計數(shù)的垃圾回收機制,閉包導致內(nèi)存泄露的一個原因就是這個算法的一個缺陷。 關(guān)于閉包,我翻了幾遍書,看了幾遍視頻,查了一些資料,可是還是迷迷糊糊的,干脆自己動手來個總結(jié)吧 !歡迎指正... (~ o ~)~zZ 1. 什么是閉包? 來看一些關(guān)于閉包的定義: 閉包是指有權(quán)...
摘要:到底什么是閉包這個問題在面試是時候經(jīng)常都會被問,很多小白一聽就懵逼了,不知道如何回答好。上面這么說閉包是一種特殊的對象。閉包的注意事項通常,函數(shù)的作用域及其所有變量都會在函數(shù)執(zhí)行結(jié)束后被銷毀。從而使用閉包模塊化代碼,減少全局變量的污染。 閉包,有人說它是一種設計理念,有人說所有的函數(shù)都是閉包。到底什么是閉包?這個問題在面試是時候經(jīng)常都會被問,很多小白一聽就懵逼了,不知道如何回答好。這個...
摘要:閉包占用大量內(nèi)存通常,函數(shù)的作用域及其所有的變量都會在函數(shù)執(zhí)行結(jié)束后被銷毀。也就是說,可以通過閉包創(chuàng)建私有作用域?qū)⒛承┳兞孔鳛榫植孔兞?,避免使用全局變量而占用過多的內(nèi)存。 JavaScript——閉包理解 1、閉包是什么,如何使用? 閉包指的是函數(shù)對象可以通過作用域鏈相互關(guān)聯(lián)起來,函數(shù)體內(nèi)部的變量都可以保存在函數(shù)作用域內(nèi),也就是說閉包有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。 下面是一...
摘要:一般來講,函數(shù)執(zhí)行完畢后,局部活動對象就會被銷毀,內(nèi)存中僅保存全局作用域,但是閉包的情況有所不同理解閉包的前提先理解另外兩個內(nèi)容作用域鏈垃圾回收作用域鏈當代碼在執(zhí)行過程中,會創(chuàng)建變量對象的一個作用域鏈。 閉包是javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包來實現(xiàn)。個人的理解是:函數(shù)中嵌套函數(shù)。 閉包的定義及其優(yōu)缺點 閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的...
閱讀 2983·2023-04-26 02:04
閱讀 1290·2021-11-04 16:07
閱讀 3718·2021-09-22 15:09
閱讀 688·2019-08-30 15:54
閱讀 1909·2019-08-29 14:11
閱讀 2537·2019-08-26 12:19
閱讀 2264·2019-08-26 12:00
閱讀 767·2019-08-26 10:27