夯實JS系列--變量、作用域和內存問題

最近在忙于寫一個react+node的全棧博客demo,沒有時間更新文章。但是還是覺得這樣一忙起來不更新是不應該的。正好在空閑上下班地鐵上都會再去細讀js原生知識。所以打算整理、總結、系統性的分享給大家。

基本類型和引用類型

在ECMAScript中,變量分為基本類型和引用類型兩種。 基本類型就是存儲簡單的數據段。而引用類型指的是那些可能由多個值構成的對象。 在ECMAScript中,基本類型包括:Undefined、Null、Boolean、Number和String。 這些基本類型的對象都是按值訪問的。所以js中我們可以直接操作他們。 但是引用類型如Object等,是按照引用來操作的。并非直接操作其值。 并且我們可以動態的為引用類型變量添加屬性和方法。而基本類型則不可以。

變量賦值和傳參

這里其實對于基本類型來說沒有什么需要重點說明的。這里就重點說下引用類型吧

對于賦值

functionsetName(obj) {obj.name="Neal";? obj=newObject();obj.name="yang";}varperson=newObject();setName(person);console.log(person.name);

如上代碼,最后console出來的是Neal。

這段代碼說明兩點:

引用類型在傳參的時候,是按照引用傳遞的,不然不可能person.name為Neal

即使在函數內部修改了參數的值。原始的引用依然不變。實際上,在重寫obj的時候,這個變量的引用已經是一個局部變量了。只是在這兒函數運行完,這個對象被銷毀了。

所以說到這,對于對象的賦值,一句以概之:引用的賦值。

執行環境及其作用域

這大概是一個非常基礎也是重要的部分,后續會在進階里面詳細展開。

執行環境定義了變量或者函數有權訪問的其他數據,決定了他們的行為。每一個執行環境都有一個與之關聯的變量對象(如global、window)。環境中定義的所有變量和函數都保存在這個對象中。

某一個執行環境執行完畢后,該環境會被銷毀。其中的所有的變量和函數也將隨之銷毀。全局執行環境知道應用程序退出才被銷毀(如關閉網頁等)

當代碼在一個環境中執行的時候,會創建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執行環境有權訪問的變量和函數的有序訪問。作用域鏈的前端,始終是當前執行的代碼所在的 環境的變量對象。全局執行環境始終是作用域鏈的最后一個對象。

標識符的解析也就是沿著作用域鏈一級一級的搜索的過程。搜索過程從作用域鏈的前端開始,然后逐級向后回溯。知道找到標識符為止。

varcolor='red';functionchangeColor() {varanotherColor='blue';functionswapColors() {vartempColor=anotherColor;? ? anotherColor=color;? ? color=tempColor;//這個執行環境中可以訪問到 tempColor color antherColor}//這里只能訪問anotherColor colorswapColors();}changeColor();//這里只能訪問color

所以從上面代碼我們可以感受到:內部環境可以通過作用域鏈訪問到外部環境的變量。反之不可。這些環境之間的聯系都是線性、有次序的。

延長作用域鏈

雖然執行環境的類型只有兩種。局部的和全局的。但是還有一種方法可以延長作用域鏈。

這是因為有些語句可以在作用域鏈的前端臨時添加一個變量對象,改變量對象會在代碼執行后被移除。

try-catch 語句中的catch

with語句

對于width語句而言,會將指定的對象添加到作用域鏈中。對于catch語句而言,會創建一個新的變量對象,其中包含被拋出的錯誤對象的申明。

關于作用域、環境之類的話題后續會再細說。這里作為基礎篇,就先介紹到這里。

垃圾收集

很開心js不需要你來收拾垃圾!好此篇完結!

好吧~雖然我們不收拾垃圾,但是也是要稍微了解下js是如何收拾垃圾的。

首先什么是垃圾:哪些不再被繼續使用的變量都是垃圾。什么叫收拾?釋放起垃圾所占用的空間即為釋放。

局部變量只在函數執行過過程中存在。而在這個過程中,會為局部變量在棧或者堆中分配相應的內存空間(存值唄)。然后函數執行啦,用了這些變量,執行完啦。完啦!則這些變量就沒有用了。沒用了,則為垃圾,既需清理。

但是并非所有的情況下都這么容易的得出結論。垃圾收集器必須跟蹤哪個變量用了哪個變量沒用。對于不在利用的打上標記,已被將來收回其所占用的內存。

標記清除

這是最為常用一種清除方式。當一個變量進入到環境的時候,標記為‘進入環境’,這個基本是不會被清除的,因為執行流進入到相應的環境的時候可能會用到。當變量離開環境的時候,標記為‘離開環境’。

可以使用任何方式來標記。我們要知道是如何標記不重要,重要的是采用什么策略。

垃圾收集器在運行的時候會給存儲在內存中的所有變量都加上標記。他會去掉環境中的變量以及被環境中的變量所引用的變量的標記。剩下的,則視為嫌疑人,準備刪除。因為環境中的變量已經無法訪問到這些變量了。目前IE、ff 、 opera 、 chrome都是這種標記清除方式

引用計數

因為不常用,簡單說下

引用計數的意思就是跟蹤記錄每一個值被引用的次數。當一個引用類型的變量復制給一個變量的時候,這個引用次數則+1,如果有別復制給另一個變量,則再+1,如果包含對這個值的引用的變量又被賦值了別的值。則這個值-1.

當引用次數為0的時候,為垃圾~回收!

為什么不常用呢?看著也很清晰啊!

look code:

functiontest() {varobjectA=newObject();varobjectB=newObject();objectA.someOtherObject=objectB;objectB.someOtherObject=objectA;}

如上,對象A和對象B的屬性互相引用。也就是說,這兩個對象的引用次數永遠都是2.哪怕這個函數執行完咯,也沒法清理的。對的,這就是bug~

節制點~你懂得

雖然垃圾回收機制幫我們做了很多事,但是電腦分配給瀏覽器的可用內存通常要比桌面應用的內存要小的多,畢竟是為了防止運行js的網頁耗盡所有的內存而導致系統崩潰的問題發生。

所以我們確保用最少的內存可以讓頁面獲取最好的性能,最佳的執行方案就是執行中的代碼都是有必要的數據。就好比用最低的經濟拿最多的人頭一樣,一旦經濟不夠,技術彌補!一旦數據不要用了,自己主動掃除。

functioncreatePerson(name) {varlocalPerson=newObject();localPerson.name=name;returnlocalPerson;}varneal=createPerson('Neal');//主動清理垃圾createPerson=null;

這里講createPerson設置為null,并沒有就把他給清除了,只是釋放了他的引用。讓其脫離其執行環境,以便于垃圾收集器更快的將其回收。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容