JavaScript變數包含的兩種不同數據類型的值——基本類型值和引用類型值的區別;ECMAScript和JavaScript的關係。 ...
本文重在探討JavaScript變數包含的兩種不同數據類型的值——基本類型值和引用類型值的區別。在此外稍微帶過ECMAScript和JavaScript的關係。
題為JavaScript變數,但更具體的說應該是ECMAScript變數。
二十世紀九十年代,Netscape公司和微軟公司推出了兩個不同版本的JavaScript,不利於JavaScript的開發和使用,促使歐洲電腦製造商協會(ECMA,European Computer Manufacturers Association)著手處理JavaScript的標準化問題,從而完成了著名的 ECMA-262——定義了一種名為ECMAScript的新腳本語言的標準。
一個完整的JavaScript實現包括ECMAScript,文檔對象模型(DOM,Document Object Model),以及瀏覽器對象模型(BOM,Browser Object Model)。ECMAScript作為JavaScript的核心以及實現的基礎,是ECMA-262標準規定的在語法、類型、語句、關鍵字、保留字、操作符和對象這幾個方面內容的語言的描述。
ECMA-262標準規定的ECMAScript變數是鬆散類型的,可以用來保存任何類型的數據,所以不同類型初始化變數的操作可以放在一條語句中執行,如下列代碼是合法的。
1 var message = "hello", //string
2 age = 20, //number
3 found = false; //boolean
用 var 操作符定義的變數將成為定義該變數的作用域中的局部變數,退出該作用域後變數會被立即銷毀。例如在函數內定義一個變數,當函數被調用的時候,該變數即被創建,但在函數退出後,該變數將無法再被繼續訪問。
ECMAScript中有6種數據類型(也只有6中,ECMAScript不支持任何創建自定義類型的機制)。
其中基本數據類型包括5種——underfinded、null、boolean、number、string,這5種基本數據類型按值訪問,其值屬於文章開頭提到的基本類型值,是簡單的數據段,可以操作保存在變數中的實際的值。
第6種為複雜數據類型——object,本質上是由一組無序的名-值對組成的,屬於引用類型值,是保存在記憶體中的對象。JavaScript不允許直接操作對象的記憶體空間,在操作對象時實際是在操作對象的引用而不是實際的對象。
雖然定義變數時不需要規定其為何種數據類型,但基本類型和引用類型的值可以執行的操作還是大相徑庭。
屬性的添加
對於引用類型的值,可以為其屬性和方法進行添加、改變和刪除,如下列代碼:
var obj = new object(); //創建對象並保存在obj中 obj.name = "Marry"; //添加名為name的屬性,賦予字元串值“Marry” alert(obj.name); //彈出"Marry"
如果obj對象不被銷毀或者name屬性不被刪除,這個屬性將一直存在。
再看基本類型值:
var name = "Marry"; //創建字元串
name.age = 20; //添加名為age的屬性,賦予number值20
alert(name.age); //彈出"underfinded"
name字元串被添加了一個age屬性,為其賦值20,但下次訪問時這個屬性就不見了。
這說明只能給引用類型值動態地添加屬性。
複製變數值
從變數a向變數b複製基本類型的值,會在變數b對象上創建一個新值,將該值複製到給變數a分配的位置上,獨立保存。這兩個變數參與的任何操作都不會互相影響。
若從變數c向變數d複製引用類型的值,同樣會將存儲在變數d對象中的值複製一份放到為變數c分配的空間中,但這個值的副本實際是一個指針,與變數d指向堆記憶體中的同一個對象。兩個變數實際引用同一個對象,改變其中一個變數,將影響另一個變數。
具體區別見如下例子:
//基本類型值 var num1 = 5; var num2 = num1; num2 = num2 + 5; alert(num1); //5 alert(num2); //10 //引用類型值 var obj1 = new object(); var obj2 = obj1; obj1.name = "Marry"; alert(obj2.name); //"Marry"
函數傳參
ECMAScript中所有函數的參數都是按值傳遞的,即將函數外部的值複製給函數內部的參數。鑒於基本類型值與引用類型值複製變數的不同,其函數傳參的效果也不同。
在向參數傳遞基本類型值時,被傳遞的參數被賦給一個局部變數,函數內部參數的變化不影響函數外部的變數;向參數傳遞引用類型值時,會把這個值在記憶體中的地址複製給一個局部變數,因此這個局部變數的變化將會反映在函數的外部。如下列例子:
//傳遞基本類型值 function addnum(num) { num += 10; return num; } var num1 = 5; var num2 = addnum(num1); alert(num1); //5,無變化 alert(num2); //15 //傳遞引用類型值 function setage(obj) { obj.age = 20; } var obj1 = new object(); setage(obj1) alert(obj1.age); //20
在局部作用域中修改的對象反映在全局作用域中,很多人會以為這是按引用傳遞。但函數對象確實都是按值傳遞,見下列例子:
function setage(obj) { obj.age = 20; obj = new object(); obj.age = 30; } var obj1 = new object(); setage(obj1) alert(obj1.age); //20
此例中在函數內部為obj重新定義了一個對象,且為其age屬性重新賦值,但這一變化並未反映在函數外部,說明obj1 並不是按引用傳遞的。實際函數內重新定義的對象為局部對象,在退出函數後就會被立即銷毀。
檢測類型
基本類型值可以通過typeof檢測,但typeof檢測引用類型時只能返回object。所以為了知道某個值是什麼類型的對象,ECMAScript提供了instandof操作符,語法如下:
result = variable instanceof constructor
如果變數是引用類型的實例,instanceof操作符就會返回true。
第一篇技術文,原本想放些實例,但想了想還是想還是從基礎的東西開始記錄。
時間也有些晚了,腦子不是很清楚((⊙o⊙)…),有錯誤和補充之處請多多指教(抱拳)