激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術(shù)及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - js教程 - js閉包和垃圾回收機制示例詳解

js閉包和垃圾回收機制示例詳解

2022-01-24 16:49丶Serendipity丶 js教程

這篇文章主要給大家介紹了關(guān)于js閉包和垃圾回收機制的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

閉包和垃圾回收機制常常作為前端學習開發(fā)中的難點,也經(jīng)常在面試中遇到這樣的問題,本文記錄一下在學習工作中關(guān)于這方面的筆記。

正文

 1.閉包

  閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現(xiàn)。作為一個JavaScript開發(fā)者,理解閉包十分重要。

  1.1閉包是什么?

  閉包就是一個函數(shù)引用另一個函數(shù)的變量,內(nèi)部函數(shù)被返回到外部并保存時產(chǎn)生,(內(nèi)部函數(shù)的作用域鏈AO使用了外層函數(shù)的AO)

       因為變量被引用著所以不會被回收,因此可以用來封裝一個私有變量,但是不必要的閉包只會增加內(nèi)存消耗。
  閉包是一種保護私有變量的機制,在函數(shù)執(zhí)行時形成私有的作用域,保護里面的私有變量不受外界干擾。或者說閉包就是子函數(shù)可以使用父函數(shù)的局部變量,還有父函數(shù)的參數(shù)。

  1.2閉包的特性

   ①函數(shù)嵌套函數(shù)

  ②函數(shù)內(nèi)部可以引用函數(shù)外部的參數(shù)和變量

  ③參數(shù)和變量不會被垃圾回收機制回收

  1.3理解閉包

  基于我們所熟悉的作用域鏈相關(guān)知識,我們來看下關(guān)于計數(shù)器的問題,如何實現(xiàn)一個函數(shù),每次調(diào)用該函數(shù)時候計數(shù)器加一。

?
1
2
3
4
5
6
7
8
var counter=0;
 function demo3(){
 console.log(counter+=1);
 }
 demo3();//1
 demo3();//2
 var counter=5;
 demo3(); //6

  上面的方法,如果在任何一個地方改變counter的值 計數(shù)器都會失效,javascript解決這種問題用到閉包,就是函數(shù)內(nèi)部內(nèi)嵌函數(shù),再來看下利用閉包如何實現(xiàn)。

?
1
2
3
4
5
6
7
8
9
10
11
function add() {
 var counter = 0;
 return function plus() {
 counter += 1;
 return counter
 }
 }
 var count=add()
 console.log(count())//1
 var counter=100
 console.log(count())//2

  上面就是一個閉包使用的實例 ,函數(shù)add內(nèi)部內(nèi)嵌一個plus函數(shù),count變量引用該返回的函數(shù),每次外部函數(shù)add執(zhí)行的時候都會開辟一塊內(nèi)存空間,外部函數(shù)的地址不同,都會重新創(chuàng)建一個新的地址,把plus函數(shù)嵌套在add函數(shù)內(nèi)部,這樣就產(chǎn)生了counter這個局部變量,內(nèi)次調(diào)用count函數(shù),該局部變量值加一,從而實現(xiàn)了真正的計數(shù)器問題。

  1.4閉包的主要實現(xiàn)形式

  這里主要通過兩種形式來學習閉包:

  ①函數(shù)作為返回值,也就是上面的例子中用到的。

?
1
2
3
4
5
6
7
8
function showName(){
 var name="xiaoming"
 return function(){
  return name
 }
 }
 var name1=showName()
 console.log(name1())

  閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來的一座橋梁。

  ②閉包作為參數(shù)傳遞

?
1
2
3
4
5
6
7
8
9
10
11
var num = 15
            var foo = function(x){
                if(x>num){
                    console.log(x)
                }  
            }
            function foo2(fnc){
                var num=30
                fnc(25)
            }
            foo2(foo)//25

上面這段代碼中,函數(shù)foo作為參數(shù)傳入到函數(shù)foo2中,在執(zhí)行foo2的時候,25作為參數(shù)傳入foo中,這時判斷的x>num的num取值是創(chuàng)建函數(shù)的作用域中的num,即全局的num,而不是foo2內(nèi)部的num,因此打印出了25。

  1.5閉包的優(yōu)缺點

  優(yōu)點:

  ①保護函數(shù)內(nèi)的變量安全 ,實現(xiàn)封裝,防止變量流入其他環(huán)境發(fā)生命名沖突

  ②在內(nèi)存中維持一個變量,可以做緩存(但使用多了同時也是一項缺點,消耗內(nèi)存)

  ③匿名自執(zhí)行函數(shù)可以減少內(nèi)存消耗

  缺點:

  ①其中一點上面已經(jīng)有體現(xiàn)了,就是被引用的私有變量不能被銷毀,增大了內(nèi)存消耗,造成內(nèi)存泄漏,解決方法是可以在使用完變量后手動為它賦值為null;

  ②其次由于閉包涉及跨域訪問,所以會導致性能損失,我們可以通過把跨作用域變量存儲在局部變量中,然后直接訪問局部變量,來減輕對執(zhí)行速度的影響。

  1.6閉包的使用

?
1
2
3
4
5
6
7
for (var i = 0; i < 5; i++) {
    setTimeout(function() {
    console.log( i);
   }, 1000);
  }
 
  console.log(i);

  我們來看上面的問題,這是一道很常見的題,可這道題會輸出什么,一般人都知道輸出結(jié)果是 5,5,5,5,5,5,你仔細觀察可能會發(fā)現(xiàn)這道題還有很多巧妙之處,這6個5的輸出順序具體是怎樣的?5 -> 5,5,5,5,5 ,了解同步異步的人也不難理解這種情況,基于上面的問題,接下來思考如何實現(xiàn)5 -> 0,1,2,3,4這樣的順序輸出呢?

?
1
2
3
4
5
6
7
8
9
for (var i = 0; i < 5; i++) {
 (function(j) { // j = i
  setTimeout(function() {
  console.log( j);
  }, 1000);
 })(i);
 }
 console.log( i);
//5 -> 0,1,2,3,4

  這樣在for循環(huán)種加入匿名函數(shù),匿名函數(shù)入?yún)⑹敲看蔚膇的值,在同步函數(shù)輸出5的一秒之后,繼續(xù)輸出01234。

?
1
2
3
4
5
6
7
for (var i = 0; i < 5; i++) {
 setTimeout(function(j) {
  console.log(j);
 }, 1000, i);
 }
 console.log( i);
 //5 -> 0,1,2,3,4

  仔細查看setTimeout的api你會發(fā)現(xiàn)它還有第三個參數(shù),這樣就省去了通過匿名函數(shù)傳入i的問題。

?
1
2
3
4
5
6
7
8
9
10
11
12
var output = function (i) {
    setTimeout(function() {
    console.log(i);
   }, 1000);
  };
 
  for (var i = 0; i < 5; i++) {
    output(i); // 這里傳過去的 i 值被復制了
  }
 
  console.log(i);
  //5 -> 0,1,2,3,4

  這里就是利用閉包將函數(shù)表達式作為參數(shù)傳遞到for循環(huán)中,同樣實現(xiàn)了上述效果。

?
1
2
3
4
5
6
7
for (let i = 0; i < 5; i++) {
      setTimeout(function() {
          console.log(new Date, i);
      }, 1000);
  }
  console.log(new Date, i);
  //5 -> 0,1,2,3,4

  知道let塊級作用域的人會想到上面的方法。但是如果要實現(xiàn)0 -> 1 -> 2 -> 3 -> 4 -> 5這樣的效果呢。

?
1
2
3
4
5
6
7
8
9
10
11
12
for (var i = 0; i < 5; i++) {
    (function(j) {
    setTimeout(function() {
     console.log(new Date, j);
   }, 1000 * j); // 這里修改 0~4 的定時器時間
   })(i);
  }
 
  setTimeout(function() { // 這里增加定時器,超時設置為 5 秒
    console.log(new Date, i);
  }, 1000 * i);
  //0 -> 1 -> 2 -> 3 -> 4 -> 5

  還有下面的代碼,通過promise來實現(xiàn)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const tasks = [];
  for (var i = 0; i < 5; i++) { // 這里 i 的聲明不能改成 let,如果要改該怎么做?
    ((j) => {
    tasks.push(new Promise((resolve) => {
     setTimeout(() => {
     console.log(new Date, j);
     resolve(); // 這里一定要 resolve,否則代碼不會按預期 work
    }, 1000 * j); // 定時器的超時時間逐步增加
   }));
   })(i);
  }
 
  Promise.all(tasks).then(() => {
    setTimeout(() => {
    console.log(new Date, i);
   }, 1000); // 注意這里只需要把超時設置為 1 秒
  });
  //0 -> 1 -> 2 -> 3 -> 4 -> 5
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const tasks = []; // 這里存放異步操作的 Promise
  const output = (i) => new Promise((resolve) => {
    setTimeout(() => {
    console.log(new Date, i);
   resolve();
   }, 1000 * i);
  });
 
  // 生成全部的異步操作
  for (var i = 0; i < 5; i++) {
    tasks.push(output(i));
  }
 
  // 異步操作完成之后,輸出最后的 i
  Promise.all(tasks).then(() => {
    setTimeout(() => {
    console.log(new Date, i);
   }, 1000);
  });
  //0 -> 1 -> 2 -> 3 -> 4 -> 5
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 模擬其他語言中的 sleep,實際上可以是任何異步操作
const sleep = (timeountMS) => new Promise((resolve) => {
 setTimeout(resolve, timeountMS);
});
 
(async () => { // 聲明即執(zhí)行的 async 函數(shù)表達式
 for (var i = 0; i < 5; i++) {
 if (i > 0) {
  await sleep(1000);
 }
 console.log(new Date, i);
 }
 
 await sleep(1000);
 console.log(new Date, i);
})();
//0 -> 1 -> 2 -> 3 -> 4 -> 5

  上面的代碼中都用到了閉包,總之,閉包找到的是同一地址中父級函數(shù)中對應變量最終的值。

  2.垃圾回收機制 

  JavaScript 中的內(nèi)存管理是自動執(zhí)行的,而且是不可見的。我們創(chuàng)建基本類型、對象、函數(shù)……所有這些都需要內(nèi)存。

  通常用采用的垃圾回收有兩種方法:標記清除、引用計數(shù)。

  1、標記清除

  垃圾收集器在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記。然后,它會去掉環(huán)境中的變量以及被環(huán)境中的變量引用的標記。

  而在此之后再被加上標記的變量將被視為準備刪除的變量,原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了。

  最后。垃圾收集器完成內(nèi)存清除工作,銷毀那些帶標記的值,并回收他們所占用的內(nèi)存空間

  2.引用計數(shù)

  引用計數(shù)的含義是跟蹤記錄每個值被引用的次數(shù)。當聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數(shù)就是1。

  相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數(shù)就減1。當這個引用次數(shù)變成0時,

  則說明沒有辦法再訪問這個值了,因而就可以將其所占的內(nèi)存空間給收回來。這樣,垃圾收集器下次再運行時,

  它就會釋放那些引用次數(shù)為0的值所占的內(nèi)存。

 總結(jié)

到此這篇關(guān)于js閉包和垃圾回收機制的文章就介紹到這了,更多相關(guān)js閉包和垃圾回收內(nèi)容請搜索服務器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/zaishiyu/p/14377502.html

延伸 · 閱讀

精彩推薦
  • js教程一篇文章教會你使用 JavaScript 創(chuàng)建對象

    一篇文章教會你使用 JavaScript 創(chuàng)建對象

    本文基于JavaScrip基礎,介紹如何去創(chuàng)建一個對象,通過從最基礎的對象屬性,對象方法,使用new Object()創(chuàng)建構(gòu)造方法,最后介紹了對象的可變性,比較對象...

    前端進階學習交流8272021-12-28
  • js教程js用正則表達式篩選年月日的實例方法

    js用正則表達式篩選年月日的實例方法

    在本篇文章里小編給大家整理的是一篇關(guān)于js用正則表達式篩選年月日的實例方法,對此有興趣的朋友們可以學習下。...

    小妮淺淺11912021-12-24
  • js教程JavaScript代碼實現(xiàn)簡單計算器

    JavaScript代碼實現(xiàn)簡單計算器

    這篇文章主要為大家詳細介紹了JavaScript代碼實現(xiàn)簡單計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    小蟲蟲~4142021-12-21
  • js教程ES6的循環(huán)與可迭代對象示例詳解

    ES6的循環(huán)與可迭代對象示例詳解

    這篇文章主要給大家介紹了關(guān)于ES6的循環(huán)與可迭代對象的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    瘋狂的技術(shù)宅11532022-01-12
  • js教程原生JS實現(xiàn)京東查看商品點擊放大

    原生JS實現(xiàn)京東查看商品點擊放大

    這篇文章主要為大家詳細介紹了原生JS實現(xiàn)京東查看商品點擊放大,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    A.香辣雞腿堡7232021-12-15
  • js教程原生js實現(xiàn)自定義滾動條

    原生js實現(xiàn)自定義滾動條

    這篇文章主要為大家詳細介紹了原生js實現(xiàn)自定義滾動條,可點擊、拖動到達,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可...

    Xaivor4202022-01-05
  • js教程js閉包的9個使用場景

    js閉包的9個使用場景

    這篇文章主要介紹了js 閉包的9個使用場景,幫助大家更好的理解和學習JavaScript 閉包的使用,感興趣的朋友可以了解下...

    林恒10102021-12-22
  • js教程JavaScript如何實現(xiàn)防止重復的網(wǎng)絡請求的示例

    JavaScript如何實現(xiàn)防止重復的網(wǎng)絡請求的示例

    這篇文章主要介紹了JavaScript如何實現(xiàn)防止重復的網(wǎng)絡請求的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    Daes11112022-01-10
主站蜘蛛池模板: 一区二区国产在线 | 成年人免费黄色片 | 欧美精品欧美 | 极品国产91在线网站 | 中文字幕伦乱 | 91九色网址| 成年免费视频黄网站在线观看 | 中文字幕一二三区芒果 | 性看小视频 | 精品一区二区在线视频 | 狠狠干天天操 | 日韩av成人 | 欧美一级免费视频 | 亚洲精品一区二区三区在线看 | 免费看操片 | 一区二区三区在线观看国产 | 黄视频免费在线观看 | 精品一区二区三区欧美 | 欧美日韩精品一区二区三区在线观看 | 欧洲狠狠鲁 | 小雪奶水翁胀公吸小说最新章节 | 奇米影视8888狠狠狠狠 | 欧美aaaaaaaa | 欧美人禽 | 羞羞视频免费视频欧美 | 欧美成人精品欧美一级乱黄 | 高潮激情aaaaa免费看 | 91看片淫黄大片欧美看国产片 | 加勒比色综合 | 精品国产一区二区三区久久久蜜月 | 精品视频在线免费看 | 国产999在线 | 高清做爰免费无遮网站挡 | 久久免费视频一区 | 激情综合在线观看 | 午夜精品久久久久久久96蜜桃 | 麻豆传传媒久久久爱 | 91精品国产综合久久婷婷香 | 暖暖免费观看高清完整版电影 | 在线香蕉视频 | av手机在线免费播放 |