javascript
JavaScript变量作用域和内存问题(js高级程序设计总结)
1,變量
????? ECMAScript和JavaScript是等同的嗎?個人認為是否定的。我的理解是這樣的,ECMAScript是一套完整的標準或者說協議,而JavaScript是在瀏覽器上實現的一套腳本語言。也就是說,ECMAScript是JavaScript的父類標準。JavaScript是ECMAScript的具體實現。所有ECMAScript定義的數據類型或者語言特性實際上都是偽代碼的形式規定的。當然如果可以,ECMAScript也可以有服務器實現,單片機實現(不一定恰當)。如果說ECMAScript是接口好像也挺形象。
????? JavaScript的基本數據類型(原始數據類型)有五種,分別是:Undefined、Null、Boolean、Number、String。基本數據類型指的是那些保存在棧內存中的簡單數據段。為什么要保存到棧內存呢?因為基本數據類型值的大小實際上是固定不變的。換句話說,這些數據是完全保存在內存中的一個位置。因為此特點所以對于基本數據類型的訪問實際上是按值訪問,因為我們實際上操作的就是保存的值。
????? JavaScript中另一種數據類型叫做引用類型值。和基本數據類型不同,引用數據內型是保存在堆內存中的對象。意思是變量中保存的實際上只是一個指針,這個指針指向內存中的另一個位置,該位置保存對象。而這個變量指針是保存在棧內存中的。同理,此類型值的訪問實際上是訪問了指向對象的指針,從而間接的訪問數據對象。
????? 下面再聊一下變量的賦值過程:
var a=1; var b=a; a++; alert(a);//2 alert(b); //1????? 很明顯了。基本數據類型的賦值操作實際上是獨立的!
????? 下面再看一個引用類型的例子:
var str = new String("hello,hz"); var newStr = str; str.name="huazi"; alert(str.name); //huazi alert(newStr.name); //huazi????? 實際上str和newStr是指向了同一塊堆內存。當然,str和newStr都是在棧內存的指針變量。
2.函數參數問題
?????? 對于JavaScript的函數傳參問題,分為兩種情況。若是基本數據類型那么就傳遞的是引用,若是對象或者引用那么就是傳遞的引用。當然你也可以理解為所有的函數參數都是值傳遞,只不過值需要分為兩種情況。值、指針。、
function test(data){return data++; } var num = 10; var res = test(num); alert(num); //10 alert(res); //11說明什么呢?值傳遞就是傳值了,沒有任何關聯關系.
var obj = new Object("hello,hz"); console.log(obj.name);//Undefiend var fun1 = function(args){args.name="huazi"return args; } var newObj = fun1(obj); console.log(newObj.name);//huazi console.log(obj.name);//huazi傳遞引用.
3.JavaScript執行環境和作用域
?????? 要理解JavaScript的作用域必須得先聊一聊JavaScript的執行環境.執行環境是JavaScript中的一個比較重要的概念.執行環境定義了一個環境變量對象與環境關聯.當然你是操作不了這個對象的.但是在瀏覽器解析腳本的時候是會用到的.執行環境中定義的函數和變量都保存在此變量對象之中.
?????? 全局的執行環境是最外圍的執行環境.根據ECMAScript的宿主環境不同,表示環境的對象也是不同的.對于JavaScript來說,宿主是瀏覽器.也就是說此全局執行環境是window對象.當某個環境的所有代碼被指向完畢之后,該環境將被銷毀.但是需要注意的是全局對象window是不被銷毀的.只有當關閉網頁或者瀏覽器時window對象才會被銷毀.
????? 每個函數在執行的時候都會創建自己的執行環境,當執行流進入一個函數時,函數的環境就會被推入一個環境棧中.執行完畢,出棧.把控制權交還給之前的執行環境.這就是ECMAScript的執行流就是用此機制控制著.
???? 作用域鏈是由變量對象構成的,作用域鏈的用途也很明確.就是保證對環境有權訪問的所有變量和函數的有序訪問.作用域的前端永遠是當前運行的代碼的變量對象.需要注意的是如果此時執行的是一個函數,那么將其活動對象作為變量對象.活動對象在最開始時候只包含一個變量,即參數對象arguments.作用域鏈中的下一個變量對象就是其父包含變量對象.變量作用域鏈的最后一個變量對象自然就是全局變量對象.
????? 變量可訪問性的判斷是根據作用域鏈來查找標識符判斷的,依次回溯.注意此處是依次回溯,所以存在優先級的問題.越靠近的變量對象越用可能被第一個找到并且調用.如果沒有找到自然報錯.
????
????? 特別的try-catch和with語句會延長作用域鏈.因為with(?)和catch(error),?和error都是只讀,所以都會被添加到所在執行環境的變量對象中.
????? JavaScript是沒有塊級作用域的.在寫for循環的時候可能需要注意一下for(var i=0;….)此種寫完,執行完for語句后i依然有值,而且不會立即釋放。
4,垃圾回收內存管理
????? JavaScript和java一樣是具有自動回收機制的,也就是說,執行環境會負責管理代碼執行過程中使用的內存。而C/C++之流是要開發人員手動跟蹤內存的使用情況的,這是造成很多問題的根源。JavaScript的垃圾回收機制很簡單:找出那些不再繼續使用的變量,然后釋放其占用的空間。為此,垃圾回收收集器會按照固定的時間間隔周期性地執行這個操作。(不同的瀏覽器對于時間間隔的定義是不同的)。
????? 回收策略:
????? 1,標記清除
????? JavaScript最常用的垃圾收集方式就是標記清除。當變量進入環境時,就將變量標記為進入環境狀態。當變量離開環境時將其標記為離開環境。可以使用任何方式來做標記,比如翻轉某個特殊位置的位來標記,或者維護一個變量列表來跟蹤標記。
????? 垃圾收集器在運行的時候回給沒個表里打上標記,然后取消掉未在環境中的變量標記。而在此后仍然帶有標記的變量就會被視為準備刪除的變量。原因是環境已經無法訪問它們了。最后就是垃圾收集器內存清除了。
????? 2,引用計數
????? 引用計數是種已經被淘汰的策略,但是在IE的某些版本中,bom和dom元素的內存管理仍然采用引用計數。因為這些對象并不是JavaScript原生,是使用C++的COM實現。而COM是使用引用計數實現。所以還是有必要了解一下。 避免循環引用造成的bug。
????? 引用計數的含義是跟蹤記錄每個值被引用的次數。當申明一個變量并且將一個引用類型值賦值給該變量時,這個值的引用次數加1.如果同一個值又被賦值給另一個值,那這個值的引用次數再加1.相反,如果包含對這個值引用的變量又取得了一個新值,則這個值的引用次數減1.當一個值的引用次數為0的時候,說明沒有辦法再來引用它了。垃圾回收。
????? 為了安全和避免一些意外情況發生,建議在使用完全局變量,全局對象屬性以及循環引用之后自行解除引用關系。obj=null;需要注意的是此種做法并沒有立刻回收內存。只是讓其脫離執行環境(肯定被標記了,下次收集器恐怕要消滅它)。
轉載于:https://www.cnblogs.com/huaziWEB/p/4480561.html
總結
以上是生活随笔為你收集整理的JavaScript变量作用域和内存问题(js高级程序设计总结)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】AngularJs 弹出框 mod
- 下一篇: C/S端开发问题汇总