變量、作用域和內存問題
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%的內存分配量,則將各種臨界值重置回默認值。
變量、作用域和內存問題