摘要:本期推薦文章類內存泄漏及如何避免,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。四種常見的內存泄漏劃重點這是個考點意外的全局變量未定義的變量會在全局對象創建一個新變量,如下。因為老版本的是無法檢測節點與代碼之間的循環引用,會導致內存泄漏。
(關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導)
本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第5天。
本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅
如果覺得本系列不錯,歡迎轉發,您的支持就是我堅持的最大動力。
本期推薦文章4類 JavaScript 內存泄漏及如何避免 ,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。
推薦理由上篇文章介紹了垃圾回收機制,但是都是些概念,今日份文章(譯文)有代碼有講解,詳解介紹了常用內存泄漏并說明了如何避免,對于提升個人知識深度非常有幫助。
閱讀筆記上篇文章詳細介紹了內存回收和內存泄漏,今天我們繼續這個篇幅,不過重點是內存泄漏可能發生的原因。沒看過上篇的點擊【進階1-4期】JavaScript深入之帶你走進內存機制
垃圾回收算法常用垃圾回收算法叫做標記清除 (Mark-and-sweep) ,算法由以下幾步組成:
1、垃圾回收器創建了一個“roots”列表。roots 通常是代碼中全局變量的引用。JavaScript 中,“window” 對象是一個全局變量,被當作 root 。window 對象總是存在,因此垃圾回收器可以檢查它和它的所有子對象是否存在(即不是垃圾);
2、所有的 roots 被檢查和標記為激活(即不是垃圾)。所有的子對象也被遞歸地檢查。從 root 開始的所有對象如果是可達的,它就不被當作垃圾。
3、所有未被標記的內存會被當做垃圾,收集器現在可以釋放內存,歸還給操作系統了。
現代的垃圾回收器改良了算法,但是本質是相同的:可達內存被標記,其余的被當作垃圾回收。
四種常見的JS內存泄漏劃重點 這是個考點
未定義的變量會在全局對象創建一個新變量,如下。
function foo(arg) { bar = "this is a hidden global variable"; }
函數 foo 內部忘記使用 var ,實際上JS會把bar掛載到全局對象上,意外創建一個全局變量。
function foo(arg) { window.bar = "this is an explicit global variable"; }
另一個意外的全局變量可能由 this 創建。
function foo() { this.variable = "potential accidental global"; } // Foo 調用自己,this 指向了全局對象(window) // 而不是 undefined foo();
解決方法:
在 JavaScript 文件頭部加上 "use strict",使用嚴格模式避免意外的全局變量,此時上例中的this指向undefined。如果必須使用全局變量存儲大量數據時,確保用完以后把它設置為 null 或者重新定義。
計時器setInterval代碼很常見
var someResource = getData(); setInterval(function() { var node = document.getElementById("Node"); if(node) { // 處理 node 和 someResource node.innerHTML = JSON.stringify(someResource)); } }, 1000);
上面的例子表明,在節點node或者數據不再需要時,定時器依舊指向這些數據。所以哪怕當node節點被移除后,interval 仍舊存活并且垃圾回收器沒辦法回收,它的依賴也沒辦法被回收,除非終止定時器。
var element = document.getElementById("button"); function onClick(event) { element.innerHTML = "text"; } element.addEventListener("click", onClick);
對于上面觀察者的例子,一旦它們不再需要(或者關聯的對象變成不可達),明確地移除它們非常重要。老的 IE 6 是無法處理循環引用的。因為老版本的 IE 是無法檢測 DOM 節點與 JavaScript 代碼之間的循環引用,會導致內存泄漏。
但是,現代的瀏覽器(包括 IE 和 Microsoft Edge)使用了更先進的垃圾回收算法(標記清除),已經可以正確檢測和處理循環引用了。即回收節點內存時,不必非要調用 removeEventListener 了。
如果把DOM 存成字典(JSON 鍵值對)或者數組,此時,同樣的 DOM 元素存在兩個引用:一個在 DOM 樹中,另一個在字典中。那么將來需要把兩個引用都清除。
var elements = { button: document.getElementById("button"), image: document.getElementById("image"), text: document.getElementById("text") }; function doStuff() { image.src = "http://some.url/image"; button.click(); console.log(text.innerHTML); // 更多邏輯 } function removeButton() { // 按鈕是 body 的后代元素 document.body.removeChild(document.getElementById("button")); // 此時,仍舊存在一個全局的 #button 的引用 // elements 字典。button 元素仍舊在內存中,不能被 GC 回收。 }
如果代碼中保存了表格某一個
閉包的關鍵是匿名函數可以訪問父級作用域的變量。
var theThing = null; var replaceThing = function () { var originalThing = theThing; var unused = function () { if (originalThing) console.log("hi"); }; theThing = { longStr: new Array(1000000).join("*"), someMethod: function () { console.log(someMessage); } }; }; setInterval(replaceThing, 1000);
每次調用 replaceThing ,theThing 得到一個包含一個大數組和一個新閉包(someMethod)的新對象。同時,變量 unused 是一個引用 originalThing 的閉包(先前的 replaceThing 又調用了 theThing )。someMethod 可以通過 theThing 使用,someMethod 與 unused 分享閉包作用域,盡管 unused 從未使用,它引用的 originalThing 迫使它保留在內存中(防止被回收)。
解決方法:
在 replaceThing 的最后添加 originalThing = null 。
PS:今晚弄到很晚,由于時間問題,就不再詳細介紹Chrome 內存剖析工具,有興趣的大家去原文查看。
周末匯總將在周日早上發送,周六會發送其他類型的文章,敬請期待。
昨日思考題解答問題一:
從內存來看 null 和 undefined 本質的區別是什么?
解答:
給一個全局變量賦值為null,相當于將這個變量的指針對象以及值清空,如果是給對象的屬性 賦值為null,或者局部變量賦值為null,相當于給這個屬性分配了一塊空的內存,然后值為null, JS會回收全局變量為null的對象。
給一個全局變量賦值為undefined,相當于將這個對象的值清空,但是這個對象依舊存在,如果是給對象的屬性賦值 為undefined,說明這個值為空值
擴展下:
聲明了一個變量,但未對其初始化時,這個變量的值就是undefined,它是 JavaScript 基本類型 之一。
var data; console.log(data === undefined); //true
對于尚未聲明過的變量,只能執行一項操作,即使用typeof操作符檢測其數據類型,使用其他的操作都會報錯。
//data變量未定義 console.log(typeof data); // "undefined" console.log(data === undefined); //報錯
值 null 特指對象的值未設置,它是 JavaScript 基本類型 之一。
值 null 是一個字面量,它不像undefined 是全局對象的一個屬性。null 是表示缺少的標識,指示變量未指向任何對象。
// foo不存在,它從來沒有被定義過或者是初始化過: foo; "ReferenceError: foo is not defined" // foo現在已經是知存在的,但是它沒有類型或者是值: var foo = null; console.log(foo); // null
問題二:
ES6語法中的 const 聲明一個只讀的常量,那為什么下面可以修改const的值?
const foo = {}; // 為 foo 添加一個屬性,可以成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另一個對象,就會報錯 foo = {}; // TypeError: "foo" is read-only
解答:
const實際上保證的,并不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對于簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同于常量。但對于復合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(即總是指向另一個固定的地址),至于它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明為常量必須非常小心。
今日思考題上面代碼的執行結果是什么?先自己分析,然后再到瀏覽器中執行。
參考4類 JavaScript 內存泄漏及如何避免往期文章查看ECMAScript 6 入門之const 命令
【進階1-1期】理解JavaScript 中的執行上下文和執行棧
【進階1-2期】JavaScript深入之執行上下文棧和變量對象
【進階1-3期】JavaScript深入之內存空間詳細圖解
【進階1-4期】JavaScript深入之帶你走進內存機制制
【進階1-5期】JavaScript深入之4類常見內存泄漏及如何避免
【進階2-1期】深入淺出圖解作用域鏈和閉包
每周計劃安排每周面試重難點計劃如下,如有修改會通知大家。每周一期,為期半年,準備明年跳槽的小伙伴們可以把本公眾號[置頂]()了。
【進階1期】 調用堆棧
【進階2期】 作用域閉包
【進階3期】 this全面解析
【進階4期】 深淺拷貝原理
【進階5期】 原型Prototype
【進階6期】 高階函數
【進階7期】 事件機制
【進階8期】 Event Loop原理
【進階9期】 Promise原理
【進階10期】Async/Await原理
【進階11期】防抖/節流原理
【進階12期】模塊化詳解
【進階13期】ES6重難點
【進階14期】計算機網絡概述
【進階15期】瀏覽器渲染原理
【進階16期】webpack配置
【進階17期】webpack原理
【進階18期】前端監控
【進階19期】跨域和安全
【進階20期】性能優化
【進階21期】VirtualDom原理
【進階22期】Diff算法
【進階23期】MVVM雙向綁定
【進階24期】Vuex原理
【進階25期】Redux原理
【進階26期】路由原理
【進階27期】VueRouter源碼解析
【進階28期】ReactRouter源碼解析
交流本人Github鏈接如下,歡迎各位Star
http://github.com/yygmind/blog
我是木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!
如果你想加群討論每期面試知識點,公眾號回復[加群]即可
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99553.html
摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...
摘要:進階期理解中的執行上下文和執行棧進階期深入之執行上下文棧和變量對象但是今天補充一個知識點某些情況下,調用堆棧中函數調用的數量超出了調用堆棧的實際大小,瀏覽器會拋出一個錯誤終止運行。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第3天。 本計劃一共28期,每期重點攻...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:本計劃一共期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅本期推薦文章深入之執行上下文棧和深入之變量對象,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第二天。 本計劃一共28期,每期...
摘要:閉包面試題解由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第8天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了...
閱讀 3478·2023-04-26 02:00
閱讀 3078·2021-11-22 13:54
閱讀 1699·2021-08-03 14:03
閱讀 709·2019-08-30 15:52
閱讀 3085·2019-08-29 12:30
閱讀 2420·2019-08-26 13:35
閱讀 3364·2019-08-26 13:25
閱讀 3001·2019-08-26 11:39