JavaScript知識總結 終結篇--面向對象,垃圾回收與記憶體泄漏

来源:https://www.cnblogs.com/smileZAZ/archive/2022/05/10/16252378.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、面向對象 一般使用字面量的形式直接創建對象,但是這種創建方式對於創建大量相似對象的時候,會產生大量的重覆代碼。但 js和一般的面向對象的語言不同,在 ES6 之前它沒有類的概念。但是可以使用函數來進行模擬,從而產生出可復用的對象創建方 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

一、面向對象

一般使用字面量的形式直接創建對象,但是這種創建方式對於創建大量相似對象的時候,會產生大量的重覆代碼。但 js和一般的面向對象的語言不同,在 ES6 之前它沒有類的概念。但是可以使用函數來進行模擬,從而產生出可復用的對象創建方式,常見的有以下幾種:

(1)第一種是工廠模式,工廠模式的主要工作原理是用函數來封裝創建對象的細節,從而通過調用函數來達到復用的目的。但是它有一個很大的問題就是創建出來的對象無法和某個類型聯繫起來,它只是簡單的封裝了復用代碼,而沒有建立起對象和類型間的關係。

(2)第二種是構造函數模式。js 中每一個函數都可以作為構造函數,只要一個函數是通過 new 來調用的,那麼就可以把它稱為構造函數。執行構造函數首先會創建一個對象,然後將對象的原型指向構造函數的 prototype 屬性,然後將執行上下文中的 this 指向這個對象,最後再執行整個函數,如果返回值不是對象,則返回新建的對象。因為 this 的值指向了新建的對象,因此可以使用 this 給對象賦值。構造函數模式相對於工廠模式的優點是,所創建的對象和構造函數建立起了聯繫,因此可以通過原型來識別對象的類型。但是構造函數存在一個缺點就是,造成了不必要的函數對象的創建,因為在 js 中函數也是一個對象,因此如果對象屬性中如果包含函數的話,那麼每次都會新建一個函數對象,浪費了不必要的記憶體空間,因為函數是所有的實例都可以通用的。

(3)第三種模式是原型模式,因為每一個函數都有一個 prototype 屬性,這個屬性是一個對象,它包含了通過構造函數創建的所有實例都能共用的屬性和方法。因此可以使用原型對象來添加公用屬性和方法,從而實現代碼的復用。這種方式相對於構造函數模式來說,解決了函數對象的復用問題。但是這種模式也存在一些問題,一個是沒有辦法通過傳入參數來初始化值,另一個是如果存在一個引用類型如 Array 這樣的值,那麼所有的實例將共用一個對象,一個實例對引用類型值的改變會影響所有的實例。

(4)第四種模式是組合使用構造函數模式和原型模式,這是創建自定義類型的最常見方式。因為構造函數模式和原型模式分開使用都存在一些問題,因此可以組合使用這兩種模式,通過構造函數來初始化對象的屬性,通過原型對象來實現函數方法的復用。這種方法很好的解決了兩種模式單獨使用時的缺點,但是有一點不足的就是,因為使用了兩種不同的模式,所以對於代碼的封裝性不夠好。

(5)第五種模式是動態原型模式,這一種模式將原型方法賦值的創建過程移動到了構造函數的內部,通過對屬性是否存在的判斷,可以實現僅在第一次調用函數時對原型對象賦值一次的效果。這一種方式很好地對上面的混合模式進行了封裝。

(6)第六種模式是寄生構造函數模式,這一種模式和工廠模式的實現基本相同,我對這個模式的理解是,它主要是基於一個已有的類型,在實例化時對實例化的對象進行擴展。這樣既不用修改原來的構造函數,也達到了擴展對象的目的。它的一個缺點和工廠模式一樣,無法實現對象的識別。

2. 對象繼承的方式有哪些?

(1)第一種是以原型鏈的方式來實現繼承,但是這種實現方式存在的缺點是,在包含有引用類型的數據時,會被所有的實例對象所共用,容易造成修改的混亂。還有就是在創建子類型的時候不能向超類型傳遞參數。

(2)第二種方式是使用借用構造函數的方式,這種方式是通過在子類型的函數中調用超類型的構造函數來實現的,這一種方法解決了不能向超類型傳遞參數的缺點,但是它存在的一個問題就是無法實現函數方法的復用,並且超類型原型定義的方法子類型也沒有辦法訪問到。

(3)第三種方式是組合繼承,組合繼承是將原型鏈和借用構造函數組合起來使用的一種方式。通過借用構造函數的方式來實現類型的屬性的繼承,通過將子類型的原型設置為超類型的實例來實現方法的繼承。這種方式解決了上面的兩種模式單獨使用時的問題,但是由於我們是以超類型的實例來作為子類型的原型,所以調用了兩次超類的構造函數,造成了子類型的原型中多了很多不必要的屬性。

(4)第四種方式是原型式繼承,原型式繼承的主要思路就是基於已有的對象來創建新的對象,實現的原理是,向函數中傳入一個對象,然後返回一個以這個對象為原型的對象。這種繼承的思路主要不是為了實現創造一種新的類型,只是對某個對象實現一種簡單繼承,ES5 中定義的 Object.create() 方法就是原型式繼承的實現。缺點與原型鏈方式相同。

(5)第五種方式是寄生式繼承,寄生式繼承的思路是創建一個用於封裝繼承過程的函數,通過傳入一個對象,然後複製一個對象的副本,然後對象進行擴展,最後返回這個對象。這個擴展的過程就可以理解是一種繼承。這種繼承的優點就是對一個簡單對象實現繼承,如果這個對象不是自定義類型時。缺點是沒有辦法實現函數的復用。

(6)第六種方式是寄生式組合繼承,組合繼承的缺點就是使用超類型的實例做為子類型的原型,導致添加了不必要的原型屬性。寄生式組合繼承的方式是使用超類型的原型的副本來作為子類型的原型,這樣就避免了創建不必要的屬性。

二、垃圾回收與記憶體泄漏

1. 瀏覽器的垃圾回收機制

(1)垃圾回收的概念

垃圾回收:JavaScript代碼運行時,需要分配記憶體空間來儲存變數和值。當變數不在參與運行時,就需要系統收回被占用的記憶體空間,這就是垃圾回收。

回收機制

  • Javascript 具有自動垃圾回收機制,會定期對那些不再使用的變數、對象所占用的記憶體進行釋放,原理就是找到不再使用的變數,然後釋放掉其占用的記憶體。
  • JavaScript中存在兩種變數:局部變數和全局變數。全局變數的生命周期會持續要頁面卸載;而局部變數聲明在函數中,它的生命周期從函數執行開始,直到函數執行結束,在這個過程中,局部變數會在堆或棧中存儲它們的值,當函數執行結束後,這些局部變數不再被使用,它們所占有的空間就會被釋放。
  • 不過,當局部變數被外部函數使用時,其中一種情況就是閉包,在函數執行結束後,函數外部的變數依然指向函數內部的局部變數,此時局部變數依然在被使用,所以不會回收。

(2)垃圾回收的方式

瀏覽器通常使用的垃圾回收方法有兩種:標記清除,引用計數。

1)標記清除

  • 標記清除是瀏覽器常見的垃圾回收方式,當變數進入執行環境時,就標記這個變數“進入環境”,被標記為“進入環境”的變數是不能被回收的,因為他們正在被使用。當變數離開環境時,就會被標記為“離開環境”,被標記為“離開環境”的變數會被記憶體釋放。
  • 垃圾收集器在運行的時候會給存儲在記憶體中的所有變數都加上標記。然後,它會去掉環境中的變數以及被環境中的變數引用的標記。而在此之後再被加上標記的變數將被視為準備刪除的變數,原因是環境中的變數已經無法訪問到這些變數了。最後。垃圾收集器完成記憶體清除工作,銷毀那些帶標記的值,並回收他們所占用的記憶體空間。

2)引用計數

  • 另外一種垃圾回收機制就是引用計數,這個用的相對較少。引用計數就是跟蹤記錄每個值被引用的次數。當聲明瞭一個變數並將一個引用類型賦值給該變數時,則這個值的引用次數就是1。相反,如果包含對這個值引用的變數又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變為0時,說明這個變數已經沒有價值,因此,在在機回收期下次再運行時,這個變數所占有的記憶體空間就會被釋放出來。
  • 這種方法會引起迴圈引用的問題:例如: obj1obj2通過屬性進行相互引用,兩個對象的引用次數都是2。當使用迴圈計數時,由於函數執行完後,兩個對象都離開作用域,函數執行結束,obj1obj2還將會繼續存在,因此它們的引用次數永遠不會是0,就會引起迴圈引用。
function fun() {
    let obj1 = {};
    let obj2 = {};
    obj1.a = obj2; // obj1 引用 obj2
    obj2.a = obj1; // obj2 引用 obj1
}

這種情況下,就要手動釋放變數占用的記憶體:

 obj1.a =  null
 obj2.a =  null

3)減少垃圾回收
雖然瀏覽器可以進行垃圾自動回收,但是當代碼比較複雜時,垃圾回收所帶來的代價比較大,所以應該儘量減少垃圾回收。
對數組進行優化:在清空一個數組時,最簡單的方法就是給其賦值為[ ],但是與此同時會創建一個新的空對象,可以將數組的長度設置為0,以此來達到清空數組的目的。
對object進行優化:對象儘量復用,對於不再使用的對象,就將其設置為null,儘快被回收。
對函數進行優化:在迴圈中的函數表達式,如果可以復用,儘量放在函數的外面。

2. 哪些情況會導致記憶體泄漏
以下四種情況會造成記憶體的泄漏:
意外的全局變數:由於使用未聲明的變數,而意外的創建了一個全局變數,而使這個變數一直留在記憶體中無法被回收。
被遺忘的計時器或回調函數:設置了 setInterval 定時器,而忘記取消它,如果迴圈函數有對外部變數的引用的話,那麼這個變數會被一直留在記憶體中,而無法被回收。
脫離 DOM 的引用:獲取一個 DOM 元素的引用,而後面這個元素被刪除,由於一直保留了對這個元素的引用,所以它也無法被回收。
閉包:不合理的使用閉包,從而導致某些變數一直被留在記憶體當中。

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • OpenHarmony電話子系統為 OS 提供了基礎的無線通信能力。支持 TD-LTE/FDD-LTE/TD-SCDMA/WCDMA/EVDO/CDMA1X/GSM 等網路制式的通信模塊,能夠提供高速的無線數據傳輸、互聯網接入等業務,具備語音、簡訊、彩信、SIM 卡等功能。 ...
  • 在直播、語聊房、K 歌房場景中,為增加趣味性和互動性,玩家可以通過變聲來搞怪,通過混響烘托氣氛,通過立體聲使聲音更具立體感。ZegoExpress SDK 提供了多種預設的變聲、混響、混響回聲、立體聲效果,開發者可以靈活設置自己想要的聲音,如果需要試聽,可以啟用耳返進行測試。 ...
  • 在 OpenHarmony 生態發展過程中,涌現了大批優秀的代碼貢獻者,本專題旨在表彰貢獻、分享經驗,文中內容來自嘉賓訪談,不代表 OpenHarmony 工作委員會觀點。 ...
  • 如今,身材管理已成為人們日常生活中重點關註的內容,除了運動之外,熱量的攝入也是重中之重,想要維持理想的身體健康和體重狀態,人們需要長期測量自己每日攝入食物的體量、熱量和營養價值,這需要實踐者有極強的耐心、執行力和知識儲備,從而成為了一部分身材管理道路上的攔路虎。 因此很多運動健康類App中支持食物識 ...
  • 今天內容挺多,因為想的是必須在一天內把這個vuex完成,說實話這裡面要記得東西還是蠻多的,主要是分為原生的和簡便方法兩種都是vue官方定義的,只不過看你要用哪種,vuex感覺要是用熟練了不得了,直接可以把vue起飛了,數據到處用,那種起飛的感覺,曾經體驗過,所以這個應該還是可以多練練的。 明天進入v ...
  • 8 個你應該立即停止使用的無效 HTML 元素 HTML 規範的開發是一個漸進的過程,有時會出現問題。隨著時間的推移,許多元素和屬性被添加到 HTML 中,直到後來 Web 社區集體意識到有更好的方法時才被刪除。由於已棄用和過時的元素和屬性已經存在於網路上,因此許多現代瀏覽器繼續支持它們的使用。儘管 ...
  • 前言 在我們日常代碼開發過程中,組件的使用是必不可少的,我們也會去封裝組件。但是大家寫組件的風格各式各樣,沒有一個統一的準則。而且也沒有遵循軟體開發的原則:高內聚、低耦合;因為我是給行業提供代碼的,行業給交付提供代碼。我們要儘量去減少大家的接入成本,降低接入成本的最好方案就是我們在設計組件的時候編寫 ...
  • HBuilderx快速新建VUE項目 一、安裝HBuilderx開發工具 官網:HBuilderX HBuilderXH是HTML的第一個字母,Builder是builder,X是HBuilder的下一個版本。我們也被稱為HX。 HBuilderX是輕量級但功能強大的 IDE。 它的官網上介紹到HB ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...