日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript作用域闭包简述

發(fā)布時(shí)間:2025/3/21 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript作用域闭包简述 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作用域

  技術(shù)一般水平有限,有什么錯(cuò)的地方,望大家指正。

  作用域就是變量起作用的范圍。作用域包括全局作用域,函數(shù)作用域以塊級(jí)作用域,ES6中的let和const可以形成塊級(jí)作用域。

  除了塊級(jí)作用域,在函數(shù)外面聲明的變量可以在任何一個(gè)地方被訪問到,這些變量的作用域都是全局作用域,全局作用域中的變量可以再任何一個(gè)地方使用:

var a = "zt"; function fn1(){console.log(a); } function fn2(){console.log(a); } fn1(); fn2();

  在函數(shù)里面聲明的變量只能在當(dāng)前函數(shù)內(nèi)使用,這些變量的作用域我們稱為函數(shù)作用域,只在當(dāng)前函數(shù)內(nèi)有效:

function fn1(){var a = "zt";console.log(a); } function fn2(){console.log(a) } fn1(); fn2();//報(bào)錯(cuò)提示a沒有定義

  函數(shù)內(nèi)定義的變量只在當(dāng)前函數(shù)內(nèi)有效,在函數(shù)以外的地方是不能被訪問到的,fn2函數(shù)內(nèi)沒有定義a,全局作用域中也沒有a使用一個(gè)不存在的變量所以報(bào)錯(cuò)。

作用域鏈

  作用域是可以嵌套的比如在全局作用域里面創(chuàng)建一個(gè)函數(shù),函數(shù)里面可以在創(chuàng)建一個(gè)函數(shù),這樣就發(fā)生了作用域的嵌套,作用域鏈可以把作用域鏈接起來。當(dāng)使用一個(gè)變量的時(shí)候,會(huì)優(yōu)先在當(dāng)前作用域內(nèi)去尋找變量,如果當(dāng)前作用域內(nèi)不存在就會(huì)去上層作用域去尋找一直到全局作用域,如果還不能找到變量就會(huì)報(bào)錯(cuò)。  

var a = "global"; function fn1(){console.log(a); } fn1();

作用域是靜態(tài)的

  我們先看一個(gè)例子:

var flag = "outer";function demo(){var flag = "inner";function inner(){console.log(flag);}return inner;}var fn = demo();fn();//inner var flag = "outer";function demo(){var flag = "inner";fn();}function fn(){console.log(flag);}demo();//outer

  通過這兩個(gè)例子我們可以看出函數(shù)的作用域是靜態(tài)的,一個(gè)函數(shù)不管在哪被調(diào)用,它的作用域都是聲明時(shí)的作用域。函數(shù)的作用域在聲明時(shí)就已經(jīng)被創(chuàng)建,在調(diào)用函數(shù)時(shí)會(huì)去訪問他已經(jīng)創(chuàng)建的作用域。

閉包

  閉包在MDN中的定義為:閉包是指那些可以訪問獨(dú)立變量的函數(shù),所以在定義上我們可以把所有的函數(shù)都看做是閉包。閉包即密閉的空間,我們可以很自然的想到函數(shù),因?yàn)楹瘮?shù)就會(huì)生成一個(gè)密閉的空間,如果函數(shù)想稱為一個(gè)閉包只需要在使用一個(gè)外部變量即可(使用外部變量的函數(shù)就是閉包)。通過閉包可以給我們帶來一些便利,就是可以在高等級(jí)的作用域使用低等級(jí)作用域中的變量:

function demo(){var flag = "test";return function(){console.log(flag);}}demo()();

  我們把demo函數(shù)里面的函數(shù)通過return使其可以在外部使用,我們已經(jīng)說過作用域都是靜態(tài)的,這樣我們?cè)谕獠渴褂胷eturn的函數(shù)時(shí),就可以看到我們?cè)谌肿饔糜蛑姓{(diào)用函數(shù)最后輸出了demo函數(shù)里面的"test"。

  這樣我們可以做一些更有意義的事:

var data = [];function demo(){var data = [];return{add:function(a){data.push(a);},print:function(){console.log(data);}}}var tool = demo();tool.add(1);tool.add(2);tool.add(3);tool.print();//[1, 2, 3]

  我們可以利用demo函數(shù)里面的data來存儲(chǔ)我們的信息而且不用擔(dān)心它被破壞(demo里面的data被私有化),而且我們也可以在外部在聲明一個(gè)同名的data來存儲(chǔ)別的信息,這兩個(gè)不會(huì)產(chǎn)生任何沖突。

  閉包也可以幫我們解決一些小問題:

for(var i=0;i<4;i++){setTimeout(function(){console.log(i);});}

  我們預(yù)期的結(jié)果是打印當(dāng)前循環(huán)的i值結(jié)果輸出全是4。先解釋一下出現(xiàn)這么情況的原因:JS是一種單線程的語言,而setTimeout是異步的,只有當(dāng)我們的代碼執(zhí)行完成以后setTimeout的處理函數(shù)才會(huì)執(zhí)行,而執(zhí)行的時(shí)候i的值已經(jīng)是4了所以最終的輸出全是4。

  我們可以通過閉包來解決這一問題:

for(var i=0;i<4;i++){(function(i){setTimeout(function(){console.log(i)})}(i))}

  閉包可以形成一個(gè)獨(dú)立的作用域這樣每次循環(huán)都會(huì)有一個(gè)獨(dú)立的函數(shù)作用域,循環(huán)完成后雖然i的值仍然是4但是setTimeout的處理函數(shù)在尋找i的時(shí)候會(huì)優(yōu)先找到作為參數(shù)的i,而每一個(gè)參數(shù)i都表示當(dāng)次循環(huán)的i,利用閉包我們可以完美的解決這種問題。

  在我們實(shí)際開發(fā)的過程中,遇到這種情況我們就可以通過閉包來解決,我們所說的"這種情況"通常有三個(gè)特點(diǎn):

  1.首先有一個(gè)循環(huán)

  2.循環(huán)里面會(huì)創(chuàng)建函數(shù),并且函數(shù)是延后執(zhí)行的

  3.這些延后執(zhí)行的函數(shù)會(huì)使用一個(gè)共同的變量,并且這個(gè)共同的變量和當(dāng)前的循環(huán)值有關(guān)系

  我們按照這個(gè)規(guī)律套一下上面的代碼:

  循環(huán)有了,每次循環(huán)也會(huì)生成一個(gè)函數(shù),這些函數(shù)也都是在循環(huán)完成后才能執(zhí)行,而且每一個(gè)函數(shù)都使用共同的i,而i就是當(dāng)前的循環(huán)值,正好符合我們的三個(gè)特點(diǎn)。我們通過(function(){}())這種方式(匿名函數(shù)自執(zhí)行)來形成一個(gè)閉包達(dá)到我們預(yù)期的目的。

  更深層次的了解,可以在網(wǎng)上查閱相關(guān)資料。

轉(zhuǎn)載自網(wǎng)絡(luò)

轉(zhuǎn)載于:https://www.cnblogs.com/wenJiaQi/p/6034138.html

總結(jié)

以上是生活随笔為你收集整理的JavaScript作用域闭包简述的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。