一、基本類型與引用過類型
說到js的變量就不得不說js變量的的類型,js變量分爲兩個類型,基本類型和引用類型。基本類型包括Undefind、Null、Boolean、Number、String。引用類型包括Object、Array、Date、RegExp、Function、基本包裝類型(Boolean/Number/String可能此處有些疑惑,稍後解釋)、單體內置對象
基本類型與引用類型的一個很大區別在於:基本類型具有固定大小的空間,因此被保存在棧內存中,基本變量是可以按值訪問的,可以直接操作變量實際的值。引用類型是保存在堆當中的,操作對象時採用的是操作對象的引用,而不是實際的值。按照我的理解就是類似於c語言當中的基本類型,在函數傳參時可以提現出來,基本類型是傳值,而引用類型是傳址。
具體區別如下:
1、引用類型具有動態的屬性,而基本類型沒有
由於基本類型保存在棧裏面,具有固定的空間大小,所有無法給基本類型添加額外的屬性,但是引用類型存在在堆裏面,可以創建額外的空間(可以理解爲c語言當中的malloc()函數,但是js在這方面做得很好,你不用擔心複雜的內存管理,js有自己的內存管理機制,後面可以瞭解到),所以可以具有動態的屬性。
eg:
var person =new Object();
person.name ="周運金"
alert("person.name"); //周運金
2、複製變量值
基本變量複製時是完全創建一個新的變量,然後把右值複製給新變量的右值,兩個變量完全獨立,互不影響。但是引用類型的變量複製時,會產生一個副本(指針),這個指針指向的是原對象值的地址空間,也就是指向同一個堆內存地址,只要其中一個變量修改了內存中的數據,另一個也會跟着改變。也就是c語言當中的傳址操作。
eg: var obj1 =new Object();
但是有一點需要注意,兩個變量除了指向同一個地址空間外,其實兩個變量是獨立的,自由的,obj2可以指向另一個地址,而這之後就跟obj1沒有任何關係了,也不貴影響到obj1(接着上面的代碼)
eg:
var obj3 ={
name:"周運金"
}
obj2 =obj3;
alert(obj1.name); //李佳家
3、參數傳遞
其實參數傳遞跟複製變量的原理是一樣的;
4、檢測類型
基本類型(null除外,typeof(null) =object)的檢測採用typeof操作符、引用類型的變量(包括null)檢測採用instanceof
eg:
alert(person intsanceof Object); //變量是否Object
alert(colors instanceof Array);
alert(pattern instanceof RegExp);
二、執行環境與作用域
i: 執行環境:執行環境定義了變量和函數有權訪問其他數據,決定他們各自的行爲。每個執行環境都有一個變量對象,環境中定義的變量和函數都在這個不可訪問的對象中。這是js自己的機制。
ii: windows對象瀏覽器默認的全局執行環境。所有的全局變量和函數都是作爲windows對象的屬性和函數。環境被銷魂保存其中的變量與函數也會被銷燬全局執行環境只有在關閉網頁或者瀏覽器時才被銷燬。
iii:作用域鏈:用來保持對執行環境中變量與函數訪問的順序的。採用就近原則,作用域的前端都是當前執行代碼所在環境的變量。一直延續到全局執行環境。
eg:
var color ="blue";
function changecolor(){
var aColor ="red";
function sColors(){
var tColor =aColor;
aColor=color;
color=tColor;
//此處可以訪問所有變量
}
sColors(); //可以訪問color和aColor但是不能訪問tColor
}
changeColor(); //只能訪問color
eg:
var color ="blue";
function getColor()
{
var color ="red";
}
alert(getColor()); //red 根據作用鏈的順序來執行
三、js沒有塊級作用域
塊級作用域:我的理解是,在一個花括號裏面包圍的環境就是一個作用域。在類C語言中,用花括號括起來的就是一個作用域。就比如一個if語句,裏面執行的代碼執行完之後就會被銷燬,如同函數一般。但是在js裏面不管用了,因爲js沒有塊級作用域,也就是說,if裏面執行的語句其實是包括在代碼最近的一個執行對象裏面。直接上代碼吧
if(true)
{
var color ="blue";
}
alert(color); //blue
for (var i=0;i<10;i++)
{
}
alert(i); //10
四、js垃圾收集機制
這個是js的一大特點,這個特點使得js不像c語言一樣要手動跟蹤內存使用情況。js的執行環境可以管理代碼執行過程中使用的內存,開發人員不用關心內存的使用問題,所需內存的分配,和回收完全實現了自動化管理。其中就涉及到兩種內存回收機制:
1、標記清除(最常用)
垃圾收集器在運行時會給存儲在內存中的所有變量加上標記。然後它會去掉環境中變量以及被環境中變量引用的標記。而在此之後再被加上標記的變量將被視爲準備刪除的變量。最後刪除那些被標記的變量
2、引用計數(IE)
引用次數爲0時刪除變量。當變量定義是引用次數爲1,賦值給另一個變量引用次數加1,想反,包含這個值引用的變量又取得一個值,則這個值得引用次數減1。但是會造成循環引用的後果。
eg:
function problem()
{
var obj1= new Object();
var obj2 =new Object();
obj1.someOtherObject =obj2;
obj2.someOtherObject =obj1;
}
五、垃圾回收機制的性能問題
垃圾回收機制是週期性進行的,所以確定這個週期是非常重要的。但是IE7以前的瀏覽器有個很嚴重問題,他是採用觸發機制的,當達到一個臨界值就觸發垃圾回收。比如256個變量、4096個對象或者數組、或者64kb字符串。如果一個腳本在他的生命週期一直保持這麼多變量,垃圾回收就會頻繁工作。後面做了改進,當內存分配少於15%時臨界值會加倍。
六、內存管理
雖然說js幫我們做了很多內存管理的工作,但是由於瀏覽器分配的內存比較少,我們還是應該合理地運用,對於一些不必再用的數據可以將值設置爲null(離開執行環境,以便垃圾回收器下次運行時回收),主要針對一些全局變量和全局對象的屬性。局部屬性的話垃圾回收器他自己會懂得。
eg:
function createPerson(name)
{
var localPerson =new Object();
localPerson.name=name;
return localPerson;
}
var globalPerson =createPerson("周運金");
alert(globalPerson.name);
globalPerson =null; //解除引用