JavaScript核心之基本概念

來源:互聯網
上載者:User

本章主要講述JavaScript中的資料類型(基本類型與參考型別),變數(包括變數的範圍),操作符(主要是一些較為常見,但是不容易從字面上理解的操作符)。由於JavaScript中的“一切皆對象”,在掌握了這些基本的概念之後,讀者就可以較為輕鬆的理解諸如範圍,調用對象,閉包,currying等等較難理解的概念了。

資料類型

有程式設計經驗的讀者肯定知道,在C或者Java這樣的語言中,資料是有類型的,比如用以表示使用者名稱的屬性是字串,而一個僱員的年齡則是一個數字,表示UI上的一個開關按鈕的資料模型則為布爾值等等,對數字可能還可以細分為浮點數,整型數,整型數又可能分為長整型和短整型,總而言之,它們都表示語言中的資料的值的類型。

JavaScript中的資料類型分為兩種:基礎資料型別 (Elementary Data Type)和物件類型,其中物件類型包含對象,數組,以及函數(事實上,函數,數組等也都是對象,這個在後邊的章節詳述)。

1.1.1 基礎資料型別 (Elementary Data Type)

在JavaScript中,包含三種基本的資料類型,字串(String),數值(Number),布爾值(boolean),下面是一些簡單的例子:

複製代碼 代碼如下:var str = "Hello, world";//字串
var i = 10;//整型數
var f = 2.3;//浮點數

var b = true;//布爾值

我們可以分別查看變數的值及變數的類型: 複製代碼 代碼如下:print(str);
print(i);
print(f);
print(b);

print(typeof str);
print(typeof i);
print(typeof f);
print(typeof b);

注意,在此處使用的print()函數為rhino解譯器的頂層對象的方法,可以用來列印字串,通常情況下,在用戶端,程式員多使用alert()進行類似的動作,alert()是瀏覽器中JavaScript解譯器的頂層對象(window)的一個方法。

Hello, world
10
2.3
true

string
number
number
Boolean
在JavaScript中,所有的數字,不論是整型浮點,都屬於“數字”基本類型。typeof是一個一元的操作符,在本章的另外一個小節會專門講到。

1.1.2 物件類型

這裡提到的對象不是對象本身,而是指一種類型,我們在第三章會對對象進行詳細的討論,此處的對象包括,對象(屬性的集合,即索引值的散列表),數組(有序的列表),函數(包含可執行檔代碼)。

物件類型是一種複合的資料類型,其基本元素由基礎資料型別 (Elementary Data Type)組成,當然不限於基本類型,比如物件類型中的值可以是其他的物件類型執行個體,我們通過例子來說明:

複製代碼 代碼如下:var str = "Hello, world";
var obj = new Object();
obj.str = str;
obj.num = 2.3;

var array = new Array("foo", "bar", "zoo");

var func = function(){
print("I am a function here");
}

可以看到,對象具有屬性,如obj.str, obj.num,這些屬性的值可以是基本類型,事實上還可以更複雜,我們來看看他們的類型: 複製代碼 代碼如下:print(typeof obj);
print(typeof array);
print(typeof func);

//將列印出
object
object
function

讀者可能會對print(typeof array)列印出object感到奇怪,事實上,對象和數組的界限並不那麼明顯(事實上它們是屬於同一類型的),但是他們的行為卻非常不同,本書的後續章節將兩個重要的資料類型做了分別介紹。

2.1.3 兩者之間的轉換

類似與Java中基礎資料型別 (Elementary Data Type)的自動裝箱拆箱,JavaScript也有類似的動作,基礎資料型別 (Elementary Data Type)在做一些運算時,會臨時封裝一個對象,做完運算後,又自動釋放該對象。我們可以通過幾個例子來說明:

複製代碼 代碼如下:var str = "JavaScript Kernal";
print(str.length);//列印17

str為一個字串,通過typeof運算子可知其type為”string”,而:

複製代碼 代碼如下:var str2 = new String("JavaScript Kernal");
print(typeof str2);

可知,str2的type為”object”,即這兩者並不相同,那麼為什麼可以使用str.length來的到str的長度呢?事實上,當使用str.length時,JavaScript會自動封裝一個臨時的String對象,內容為str的內容,然後擷取該對象的length屬性,最後,這個臨時的對象將被釋放。

而將對象轉換為基本類型則是通過這樣的方式:通過調用對象的valueOf()方法來取得對象的值,如果和內容相關的類型匹配,則使用該值。如果valueOf取不到值的話,則需要調用對象的toString()方法,而如果上下文為數值型,則又需要將此字串轉換為數值。由於JavaScript是弱類型的,所以JavaScript引擎需要根據上下文來“猜測”對象的類型,這就使得JavaScript的效率比編譯型的語言要差一些。

valueOf()的作用是,將一個對象的值轉換成一種合乎上下文需求的基本類型,toString()則名副其實,可以列印出對象對應的字串,當然前提是你已經“重載”了Object的toString()方法。

事實上,這種轉換規則會導致很多的問題,比如,所有的非Null 物件,在布爾值環境下,都會被轉成true,比如: 複製代碼 代碼如下:function convertTest(){
if(new Boolean(false) && new Object() &&
new String("") && new Array()){
print("convert to boolean")
}
}
convertTest();//convert to Boolean

初學者容易被JavaScript中的類型轉換規則搞暈掉,很多情況下會覺得那種寫法看著非常彆扭,其實只需要掌握了規則,這些古怪的寫法會大大的提高代碼的效能,我們通過例子來學習這些規則: 複製代碼 代碼如下:var x = 3;
var y = x + "2";// => 32
var z = x + 2;// => 5

print(y);
print(z);

通常可以在JS代碼中發現這樣的代碼:

複製代碼 代碼如下:if(datamodel.item){
//do something...
}else{
datamodel.item = new Item();
}

這種寫法事實上具有更深層次的含義:

應該注意到,datamodel.item是一個對象(字串,數字等),而if需要一個boolean型的運算式,所以這裡進行了類型轉換。在JavaScript中,如果上下文需要boolean型的值,則引擎會自動將對象轉換為boolean類型。轉換規則為,如果該對象非空,則轉換為true,否則為false.因此我們可以採取這種簡寫的形式。

而在傳統的程式設計語言(強型別)中,我們則需要:

複製代碼 代碼如下:if(datamodel.item != null){
//do something...
}else{
datamodel.item = new Item();
}

2.1.4類型的判斷

前面講到JavaScript特性的時候,我們說過,JavaScript是一個弱類型的語言,但是有時我們需要知道變數在運行時的類型,比如,一個函數的參數預期為另一個函數:

複製代碼 代碼如下:function handleMessage(message, handle){
return handle(message);
}

當調用handleMessage的函數傳遞的handle不是一個函數則JavaScript引擎會報錯,因此我們有必要在調用之前進行判斷:

複製代碼 代碼如下:function handleMessage(message, handle){
if(typeof handle == "function"){
return handle(message);
}else{
throw new Error("the 2nd argument should be a function");
}
}

但是,typeof並不總是有效,比如下面這種情況:

複製代碼 代碼如下:var obj = {};
var array = ["one", "two", "three", "four"];

print(typeof obj);//object
print(typeof array); //object

運行結果顯示,對象obj和數組array的typeof值均為”object”,這樣我們就無法準確判斷了,這時候,可以通過調用instanceof來進行進一步的判斷:

print(obj instanceof Array);//false
print(array instanceof Array);//true
第一行代碼返回false,第二行則返回true。因此,我們可以將typeof操作符和instanceof操作符結合起來進行判斷。

2.2 變數

變數,即通過一個名字將一個值關聯起來,以後通過變數就可以引用到該值,比如:

複製代碼 代碼如下:var str = "Hello, World";
var num = 2.345;

當我們下一次要引用”Hello, Wrold”這個串進行某項操作時,我們只需要使用變數str即可,同樣,我們可以用10*num來表示10*2.345。變數的作用就是將值“儲存”在這個變數上。

2.2.1基本類型和參考型別

在上一小節,我們介紹了JavaScript中的資料類型,其中基本類型如數字,布爾值,它們在記憶體中都有固定的大小,我們通過變數來直接存取基本類型的資料。而對於參考型別,如對象,數組和函數,由於它們的大小在原則上是不受任何限制的,故我們通過對其引用的訪問來訪問它們本身,引用本身是一個地址,即指向真實儲存複雜物件的位置。

基本類型和參考型別的區別是比較明顯的,我們來看幾個例子:

複製代碼 代碼如下:var x = 1;//數字x,基本類型
var y = x;//數字y,基本類型
print(x);
print(y);

x = 2;//修改x的值

print(x);//x的值變為2
print(y);//y的值不會變化

運行結果如下:

1

1

2

1

這樣的運行結果應該在你的意料之內,沒有什麼特別之處,我們再來看看參考型別的例子,由於數組的長度非固定,可以動態增刪,因此數組為參考型別:

複製代碼 代碼如下:var array = [1,2,3,4,5];
var arrayRef = array;

array.push(6);
print(arrayRef);

引用指向的是地址,也就是說,引用不會指向引用本身,而是指向該引用所對應的實際對象。因此通過修改array指向的數組,則arrayRef指向的是同一個對象,因此運行效果如下:

1,2,3,4,5,6

2.2.2變數的範圍

變數被定義的地區即為其範圍,全域變數具有全域範圍;局部變數,比如聲明在函數內部的變數則具有局部範圍,在函數的外部是不能直接存取的。比如:

複製代碼 代碼如下:var variable = "out";

function func(){
var variable = "in";
print(variable);//列印”in”
}

func();
print(variable);//列印”out”

應該注意的是,在函數內var關鍵字是必須的,如果使用了變數而沒有寫var關鍵字,則預設的操作是對全域對象的,比如:

複製代碼 代碼如下:var variable = "out";

function func(){
variable = "in";//注意此variable前沒有var關鍵字
print(variable);
}

func();
print(variable);//全域的變數variable被修改

由於函數func中使用variable而沒有關鍵字var,則預設是對全域對象variable屬性做的操作(修改variable的值為in),因此此段代碼會列印:

in

in

2.3運算子

運算子,通常是容易被忽略的一個內容,但是一些比較古怪的文法現象仍然可能需要用到運算子的結合率或者其作用來進行解釋,JavaScript中,運算子是一定需要注意的地方,有很多具有JS編程經驗的人仍然免不了被搞得暈頭轉向。

我們在這一節主要講解這樣幾個運算子:

2.3.1中括弧運算子([])

[]運算子可用在數組對象和對象上,從數組中按下標取值:

複製代碼 代碼如下:var array = ["one", "two", "three", "four"];
array[0]

而[]同樣可以作用於對象,一般而言,對象中的屬性的值是通過點(.)運算子來取值,如:

複製代碼 代碼如下:var object = {
field : "self",
printInfo : function(){
print(this.field);
}
}

object.field;
object.printInfo();

但是考慮到這樣一種情況,我們在遍曆一個對象的時候,對其中的屬性的鍵(key)是一無所知的,我們怎麼通過點(.)來訪問呢?這時候我們就可以使用[]運算子:

複製代碼 代碼如下:for(var key in object){
print(key + ":" + object[key]);
}

運行結果如下:

field:slef
printInfo:function (){
print(this.field);
}
2.3.2點運算子(.)

點運算子的左邊為一個對象(屬性的集合),右邊為屬性名稱,應該注意的是右邊的值除了作為左邊的對象的屬性外,同時還可能是它自己的右邊的值的對象:

複製代碼 代碼如下:var object = {
field : "self",
printInfo : function(){
print(this.field);
},
outter:{
inner : "inner text",
printInnerText : function(){
print(this.inner);
}
}
}

object.outter.printInnerText();

這個例子中,outter作為object的屬性,同時又是printInnerText()的對象。

2.3.3 == 和 === 以及 != 和 !==

運算子==讀作相等,而運算子===則讀作等同。這兩種運算子操作都是在JavaScript代碼中經常見到的,但是意義則不完全相同,簡而言之,相等操作符會對兩邊的運算元做類型轉換,而等同則不會。我們還是通過例子來說明:

print(1 == true);
print(1 === true);
print("" == false);
print("" === false);

print(null == undefined);
print(null === undefined);
運行結果如下:

複製代碼 代碼如下:true
false
true
false
true
false

相等和等同運算子的規則分別如下:

相等運算子

如果運算元具有相同的類型,則判斷其等同性,如果兩個運算元的值相等,則返回true(相等),否則返回false(不相等).

如果運算元的類型不同,則按照這樣的情況來判斷:

◆ null和undefined相等

◆ 其中一個是數字,另一個是字串,則將字串轉換為數字,在做比較

◆ 其中一個是true,先轉換成1(false則轉換為0)在做比較

◆ 如果一個值是對象,另一個是數字/字串,則將對象轉換為原始值(通過toString()或者valueOf()方法)

◆ 其他情況,則直接返回false

等同運算子

如果運算元的類型不同,則不進行值的判斷,直接返回false

如果運算元的類型相同,分下列情況來判斷:

◆ 都是數位情況,如果值相同,則兩者等同(有一個例外,就是NaN,NaN與其本身也不相等),否則不等同

◆ 都是字串的情況,與其他程式設計語言一樣,如果串的值不等,則不等同,否則等同

◆ 都是布爾值,且值均為true/false,則等同,否則不等同

◆ 如果兩個運算元引用同一個對象(數組,函數),則兩者完全等同,否則不等同

◆ 如果兩個運算元均為null/undefined,則等同,否則不等同

比如:

複製代碼 代碼如下:var obj = {
id : "self",
name : "object"
};

var oa = obj;
var ob = obj;

print(oa == ob);
print(oa === ob);

會返回:

true

true

再來看一個對象的例子:

複製代碼 代碼如下:var obj1 = {
id : "self",
name : "object",
toString : function(){
return "object 1";
}
}

var obj2 = "object 1";

print(obj1 == obj2);
print(obj1 === obj2);

傳回值為:

true

false

obj1是一個對象,而obj2是一個結構與之完全不同的字串,而如果用相等操作符來判斷,則兩者是完全相同的,因為obj1重載了頂層對象的toString()方法。

而!=不等和!==不等同,則與==/!==相反。因此,在JavaScript中,使用相等/等同,不等/不等同的時候,一定要注意類型的轉換,這裡推薦使用等同/不等同來進行判斷,這樣可以避免一些難以調試的bug。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.