1. 程式人生 > >變量、作用域和內存問題

變量、作用域和內存問題

素數 bsp 實現 fire 變量聲明 fin 值傳遞 語句 作用域

1 基本類型和引用類型的值

ECMAScript可能包含兩種不同數據類型的值:

  • 基本類型值——簡單的數據段
  • 引用類型值——可能由多個值構成的對象

1.1 動態的屬性

可以動態地為引用類型值添加或刪除屬性和方法:

var person = new Object();
person.name = "Nicholas";
alert("person.name");        //"Nicholas"

不能給基本類型添加屬性,盡管不會導致任何錯誤:

var name = "Nicholas";
name.age = 27;
alert("name.age");            //undefined

1.2 復制變量值

基本類型:創建的是原來變量的一個副本,是兩個完全獨立的變量,修改其中之一不會影響另一個。

var num1 = 5;
var num2 = num1;
num1 = 10;
alert("num1");            //10
alert("num2");            //5

引用類型:創建的是對象的指針,指向原來的變量指向的對象。改變其中一個變量會影響另一個變量。

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name);                
//"Nicholas"

1.3 傳遞參數

ECMAscript中所有函數的參數都是按值傳遞的。基本類型的傳遞和基本類型復制一樣,而引用類型傳遞即和引用類型復制一樣。

基本類型:

function addTen(num) {
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
alert(count);                      //20      
alert(result);                     //30

引用類型:

function setName(obj) {
    obj.name 
= "Nicholas"; //這裏的obj為傳入的參數的一個(指針)副本,其指向傳入參數指向的對象,可以用其來為其指向的對象添加屬性。 } var person = new Object(); setName(person); alert(person.name); //"Nicholas
1 function setName(obj) {
2     obj.name = "Nicholas";             //obj指向的對象與傳入參數指向的對象相同,這裏obj為其指向的對象添加了name屬性
3     obj = new Object();               //obj指向了一個新的局部對象
4     boj.name = "Greg";               //為這個局部對象添加name屬性
5 }                                    //脫離了作用域,obj指向的局部對象被銷毀
6 
7 var person = new Object();
8 setName(person);    
9 alert(person.name);

檢測類型:

typeof操作符:

1 var u;
2 var n = null;
3 var o = new Object();
4 
5 alert(typeof u);            //undefined
6 alert(typeof n);            //object
7 alert(typeof o);            //object

typeof檢測函數時返回"function"。在Safari5及之前版本與chrome及之前版本用typeof檢測正則表達式返回"function",因為ECMA-262規定任何內部實現了[[Call]]方法的對象在應用typeof操作符時返回"function"。

而在IE和Firefox中對正則表達式應用typeof返回“object”。

instanceof操作符:

語法: result = variable instanceof constructor

如果變量是給定引用類型(根據它的原型鏈來識別)的實例,那麽instanceof操作符就返回true。

2 執行環境及作用域

內部作用域可以訪問外部作用域的局部變量,反之則不能。函數參數被當作變量來對待,因此其訪問規則與作用域中其他變量的訪問規則相同。

2.1 延長作用域鏈

當執行流進入下列任何一個語句時,作用域鏈就會得到加長:

  • try-catch語句的catch塊
  • with語句

2.2 沒有塊級作用域

if語句和for語句中的變量聲明會將變量添加到當前的執行環境,這點與其他類C語言不同。

 1 if (true) {
 2     var color = "blue";
 3 }          //在C、C++等語言中,此時color因離開作用域而被銷毀,但是javascript中不會。
 4 
 5 alert(color);        //"blue"
 6 
 7 for (var i = 0; i < 10; ++i) {
 8     doSomething(i);
 9 }          // 在C、C++等語言中,此時 i 因離開作用域而被銷毀,但是javascript中不會。
10 alert(i);            //10

變量聲明:var聲明的變量會被自動添加到就近環境。初始化變量沒有使用var聲明,變量會被自動添加到全局環境。

!!!不聲明而直接初始變量是一個常見的錯誤做法,因為可能導致意外。建議在初始化變量之前一定要聲明變量。

查詢標識符:標識符查詢是從內往外逐層查詢,直到找到標識符或搜索到全局作用域為止。一旦找到標識符,立即停止搜索。內層作用域的同名變量會覆蓋外層作用域的同名變量。

3 垃圾收集

JavaScript具有自動垃圾手機機制,通常有兩種策略:

  • 標記清除:垃圾收集器在運行的時候給存儲在內存中的變量都加上標記,然後去掉環境中的變量以及被環境中變量引用的變量的標記,在此之後再被標記的變量將被視為準備刪除的變量。
  • 引用計數:值被引用或復制時引用計數加1,而包含對這個值的引用的變量取得另一個值時引用次數減1。當引用計數為0時內存將被釋放。(不常用)

IE7垃圾回收例程工作方式:如果垃圾收集例程回收的內存分配量低於15%,則變量、字面量和元素數組的臨界值會加倍。如果內存回收了85%的內存分配量,則將各種臨界值重置回默認值。

變量、作用域和內存問題