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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从闭包函数的变量自增的角度 - 解析js垃圾回收机制

發布時間:2024/4/17 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从闭包函数的变量自增的角度 - 解析js垃圾回收机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

GitHub

前言

感覺每一道都可以深入研究下去,單獨寫一篇文章,包括不限于閉包,原型鏈,從url輸入到頁面展示過程,頁面優化,react和vue的價值等等。

代碼實現

const times = (()=>{var times = 0;return () => times++; })() console.log(times(),times(),times(),times() ) // 0,1,2,3,復制代碼

原理

因為times變量一直被引用,沒有被回收,所以,每次自增1。

更簡單的實現方式,一行代碼實現閉包

const times = ((times = 0)=> () => times++)() console.log(times(),times(),times(),times() ) // 0,1,2,3復制代碼

這并非閉包地專利, 變量放在閉包外部同樣可以實現阻止變量地垃圾回收機制

let time = 0 const times = ()=>{let time = 10return function(){return time++} }// 根據JavaScript作用域鏈地規則,閉包內部沒有,就從外面拿變量const a = times(); // times函數只被執行了1次,產生了一個變量 time console.log(a(), // 而times返回的匿名函數卻被執行了5次a(), // 而times返回的匿名函數卻被執行了5次a(), // 而times返回的匿名函數卻被執行了5次 其中的差別相差非常遠a(), // 而times返回的匿名函數卻被執行了5次a() // 而times返回的匿名函數卻被執行了5次 ) // 0,1,2,3復制代碼

深入寫下去之前,先放出類似的代碼

同樣的執行,我把函數執行時間放到了前面,自增失敗

const times = ((times = 0)=> () => times++)()(); 匿名函數只被執行了一次,同時返回函數再次執行一次 console.log(times, // 得到匿名函數返回值, 函數只有配合()才會被執行一次么,此處times, // 此處沒有函數被執行times, // 因此打印值為四個零times ); // 0,0,0,0復制代碼

同樣的執行,我把閉包函數執行時間放到了后面,同樣自增失敗

const times = ((times = 0)=> () => times++); time相當于聲明式函數 console.log(times()(), // 此處外部函數執行一次,產生times變量,返回的函數再執行一次times引用次數為0times()(), // 此處外部函數執行一次,產生times變量,返回的函數再執行一次times()(), // 此處外部函數執行一次,產生times變量,返回的函數再執行一次times()() ); // 0,0,0,0復制代碼

函數[1,2,3,4,4].entires()會返回一個迭代器,一下代碼同樣實現了類似自增1的效果

const arr = [1,2,3,3,5,6,4,78].entries() console.log(arr2.next().value,arr2.next().value,arr2.next().value,arr2.next().value,arr2.next().value ); // [0, 1], [1, 2], [2, 3], [3, 3], [4, 5] 迭代器返回值, 【index,value】復制代碼

JavaScript辣雞回收機制

按照JavaScript里垃圾回收的機制,是從root(全局對象)開始尋找這個對象的引用是否可達,如果引用鏈斷裂,那么這個對象就會回收。換句話說,所有對象都是point關系。引用鏈就是所謂的指針關系。
當const的過程中,聲明的那個函數會被壓入調用棧,執行完畢,又沒有其他地方引用它,那就會被釋放。這個瀏覽器端,挺難的,但是在nodejs端,就可以用process.memoryUsage()調用查看內存使用情況。

{ rss: 23560192, // 所有內存占用,包括指令區和堆棧。heapTotal: 10829824, // "堆"占用的內存,包括用到的和沒用到的。heapUsed: 4977904, // 用到的堆的部分。同時也是判斷內存是否泄露的標準。external: 8608 // V8 引擎內部的 C++ 對象占用的內存。 }復制代碼
如果你想要引用,又不想影響垃圾回收機制,那就用WeakMap,WeakSet這種弱引用吧,es6的新屬性。

從引用次數來解釋為什么變量times沒有被回收

const timeFunc = ((time = 0)=> () => time++) var b = timeFunc(); // time 變量引用次數+1,不能被回收 console.log(b()); console.log(b()); console.log(b());復制代碼// 真的非常神奇,需要滿足2個條件 // 1.變量命名于返回函數外部,函數函數內部。 // 2.返回函數引用外部變量,導致外部變量無法觸發垃圾回收機制。因為引用次數>1 let timeFunc = (time = 0)=>{return (() => time++)() } var b = timeFunc(); // b變量接受的是timeFunc返回的函數,由于返回函數內部有引用外部變量,故 console.log(b) console.log(b)復制代碼

JavaScript中的內存簡介(如果缺少必須的基礎知識,想要深入了解下去,也是比較難的吧)

像C語言這樣的高級語言一般都有低級的內存管理接口,比如 malloc()和free()。另一方面,JavaScript創建變量(對象,字符串等)時分配內存,并且在不再使用它們時“自動”釋放。 后一個過程稱為垃圾回收。這個“自動”是混亂的根源,并讓JavaScript(和其他高級語言)開發者感覺他們可以不關心內存管理。 這是錯誤的。

閉包的本質

JavaScript閉包的形成原理是基于函數變量作用域鏈的規則 和 垃圾回收機制的引用計數規則。
JavaScript閉包的本質是內存泄漏,指定內存不釋放。
(不過根據內存泄漏的定義是無法使用,無法回收來說,這不是內存泄漏,由于只是無法回收,但是可以使用,為了使用,不讓系統回收)
JavaScript閉包的用處,私有變量,獲取對應值等,。。

內存生命周期

不管什么程序語言,內存生命周期基本是一致的:

  • 分配你所需要的內存
  • 使用分配到的內存(讀、寫)
  • 不需要時將其釋放\歸還

在所有語言中第一和第二部分都很清晰。最后一步在底層語言中很清晰,但是在像JavaScript 等上層語言中,這一步是隱藏的、透明的。

為了不讓程序員操心(真的是操碎了心),JavaScript自動完成了內存分配工作。

var n = 123; // 給數值變量分配內存 var s = "azerty"; // 給字符串變量分配內存var obj = {a: 1,b: null }; // 給對象以及其包含的值分配內存var arr = [1,null,"abra"]; // 給函數(可調用的對象)分配內存function f(a){return a+2 } // 給函數(可調用對象)分配內存// 為函數表達式也分配一段內存 document.body.addEventListener('scroll', function (){console.log('123') },false)復制代碼

有些函數調用之后會返回一個對象

var data = new Date(); var a = document.createElement('div');復制代碼

有些方法是分配新變量或者新對象

var s1 = 'azerty'; // 由于字符串屬于引用,所以JavaScript不會為他分配新的內存 var s2 = 's.substr(0,3)'; // s2是一個新的字符串var a = ["ouais ouais", "nan nan"]; var a2 = ["generation", "nan nan"]; var a3 = a.concat(a2); // 新數組有四個元素,是 a 連接 a2 的結果復制代碼

命名變量的過程其實是對內存的寫入和釋放

辣雞回收

如上文所述,內存是否仍然被需要是無法判斷的,下面將介紹垃圾回收算法以及垃圾回收的局限性

引用

辣雞回收算法主要依賴于引用的概念。在內存管理的環境中,如果一個對象有訪問另一個對象的權限,那么對于屬性屬于顯示引用,對于原型鏈屬于隱式引用。

引用計數垃圾收集

下面是最簡單的垃圾回收算法。此算法把“對象是否被需要”簡單定義為“該對象沒有被其他對象引用到”。

var o = {a: {b: 2} }; // 兩個對象被創建,一個作為另一個的屬性被引用,另一個被分配給變量o // 很顯然,沒有一個可以被作為辣雞收集var o2 = o; // o2變量是第二個對“這個對象”o = 1; // 現在這個對象的原始引用o被o2替換了var oa = o2.a; // 引用“這個對象”的a屬性// 現在,“這個對象”有兩個引用了,一個是o2,一個是oao2 = 'yo'; // 最初的對象現在已經是零引用了// 它可以被垃圾回收了// 然而他的屬性a還在被調用,所以不能回收oa = null; // a屬性的那個對象現在也是零引用了// 它可以被垃圾回收了復制代碼


與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的从闭包函数的变量自增的角度 - 解析js垃圾回收机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。