### 3.1 語法
ECMAScript中的一切(變量名、函數(shù)名、屬性名、參數(shù)名、操作符)都區(qū)分大小寫。
所謂**標識符**,就是指變量、函數(shù)、屬性的名字,或者函數(shù)的參數(shù)。
* ***第一個字符必須是字母、下劃線_、或美元符號$;***
* ***第二個字符可以使字母、下劃線_、美元符號$或數(shù)字。***
***按照慣例,ECMAScript標識符采用駝峰大小寫格式。***
### 3.3 變量
`var message;`
這行代碼定義了一個名為message的變量,該變量可以用來保存任何值(像這樣未經(jīng)過初始化的變量,會保存一個特殊的值--undefined)。使用var操作符定義的變量將成為該變量的作用域中的局部變量,而省略var操作符會創(chuàng)建一個全局變量。
### 3.4 數(shù)據(jù)類型
ECMAScript中有5種簡單數(shù)據(jù)類型(也稱為基本數(shù)據(jù)類型):Undeifined、Null、Boolean、Number和String。還有一種復雜數(shù)據(jù)類型--Object,Object本質(zhì)上是由一組無序的名值對組成的。
#### 3.4.1 typeof操作符
typeof操作符用于檢測給定變量的數(shù)據(jù)類型。對一個值使用typeof操作符可能返回下列某個字符串(均為小寫字母):
* “undefined”----如果這個值未定義;
* “boolean”----如果這個值是布爾值;
* “string”----如果這個值是字符串;
* “number”----如果這個值是數(shù)值;
* **“object”----如果這個值是對象(包括正則表達式)或者null;**
* **“function”----如果這個值是函數(shù)。**
#### 3.4.2 Undefined類型
Undefined類型只有一個值,即特殊的undefined。在使用var聲明變量但未對其加以初始化(個人理解:初始化等同于賦值)時,這個變量的值就是undefined,例如:
~~~
var message;
alert(message == undifined); //true
~~~
對于尚未聲明過的變量,只能執(zhí)行一項操作,即使用typeof操作符檢測其數(shù)據(jù)類型(其他操作均會產(chǎn)生錯誤)。然而令人困惑的是:**對未初始化的變量執(zhí)行typeof操作符會返回undefined值,而對未聲明的變量執(zhí)行typeof操作符同樣也會返回undefined值**。因此,即使未初始化的變量會自動被賦與undefined值,但顯式地初始化變量依然是明智的選擇。如果能夠做到這一點,那么當typeof操作符返回”undefined”值時,我們就知道被檢測的變量還沒有被聲明,而不是尚未初始化。
*****
如果只是聲明了一個變量而不是馬上對其實際賦值,那么將其初始化的最佳實踐個人總結(jié)如下:
* ***Boolean類型賦值為true/false;***
* ***Number類型賦值為0;***
* ***String類型賦值為空字符串;***
* ***Object類型(空對象)賦值為null;***
#### 3.4.4 Boolean類型
要將一個值轉(zhuǎn)換為其對應的布爾值,可以調(diào)用轉(zhuǎn)型函數(shù)Boolean()。雖然Boolean類型的字面值只有兩個,但ECMAScript中所有類型的值都有與這兩個布爾值等價的值。各種數(shù)據(jù)類型及其對應的布爾值轉(zhuǎn)換規(guī)則見P26。**流控制語句(如if語句)自動執(zhí)行相應的Boolean轉(zhuǎn)換(自動調(diào)用Boolean()函數(shù))**。
#### 3.4.5 Number類型
Number類型的注意點包括:
- ***永遠不要測試某個特定的浮點數(shù)值***。
- ECMAScript中整數(shù)除了能以十進制表示外,還可以通過八進制或十六進制的字面值來表示。
- 如果某次計算返回了正或負的Infinity值,那么該值將無法繼續(xù)參與下一次的計算。要想確定一個數(shù)值是不是有窮的,可以使用isFinite()函數(shù)。這個函數(shù)會在參數(shù)位于最小與最大數(shù)值之間時返回true。
- 任何涉及NaN的計算操作都會返回NaN,這個特點在多步計算中有可能導致問題;NaN與任何值都不相等,包括NaN本身。
- IsNaN()函數(shù)用于判斷參數(shù)是否“不是數(shù)值”,isNaN()函數(shù)的參數(shù)可以為任何類型,在接收到一個值之后,會嘗試將這個值轉(zhuǎn)換為數(shù)值(個人推測是調(diào)用Number()函數(shù))。
- Number()函數(shù)可用于任何類型的轉(zhuǎn)換,而parseInt()、parstFloat()函數(shù)則專門用于把字符串轉(zhuǎn)換成數(shù)值,它們之間的主要區(qū)別有兩個:
1. Number()函數(shù)不接受任何包含非數(shù)字的字符串(返回NaN),而后兩者的參數(shù)只要第一個非空字符為數(shù)字即會返回數(shù)值,數(shù)字后的字符串將被忽略。
2. 是Number()函數(shù)對空字符串會返回數(shù)值0,而后兩者會返回NaN。
此外,Number()函數(shù)會將undefined值轉(zhuǎn)換為NaN而不是0。
#### 3.4.6 String類型
字符字面量中的轉(zhuǎn)義序列詳見P33。他們的一致特點是用反斜杠”\”開頭。(最常用的\n表示換行)
*****
要把一個值轉(zhuǎn)換為一個字符串有兩種方式。第一種是使用每個引用類型值都有的toString()方法,但null和undefined沒有這個方法。第二種是在不知道要轉(zhuǎn)換的值是不是null或undefined的情況下使用轉(zhuǎn)型函數(shù)String(),這個函數(shù)可以把所有類型值轉(zhuǎn)換為相應的字符串。
#### 3.4.7 Object類型
ECMAScript中的對象其實就是一組數(shù)據(jù)和功能的集合。對象可以通過執(zhí)行new操作符后跟要創(chuàng)建的對象類型的名稱來創(chuàng)建。**而創(chuàng)建Object類型的實例并為其添加屬性和(或)方法,就可以創(chuàng)建自定義對象**。
*****
創(chuàng)建一個Object類型**實例**的基本語法:
`var o = new Object();`
*****
在ECMAScript中,Object類型是所有它的實例的基礎。換句話說,Object類型所具有的任何屬性和方法也同樣存在于更具體的對象中。
***Object的每個實例都具有下列屬性和方法***:
* constructor:保存著用于創(chuàng)建當前對象的函數(shù)。對于前面的例子而言,構(gòu)造函數(shù)(constructor)就是Object()。
* hasOwnProperty(propertyName):用于檢查給定的屬性在當前對象實例中(而不是在實例的原形中)是否存在。其中,作為參數(shù)的屬性名(propertyName)必須以字符串形式指定。(例如:o.hasOwnProperty(‘name’);)。
* isPrototypeOf(Object):用于檢查當前對象是否是傳入對象的原型。
* propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用for-in語句來枚舉。
* toLocaleString():返回對象的字符串表示,該字符串與執(zhí)行環(huán)境的地區(qū)對應。
* toString():返回對象的字符串表示;
* valueOf():返回對象的字符串、數(shù)值或布爾值表示。通常與toString()方法的返回值相同。
由于在ECMAScript中Object對象是所有對象的基礎,因此所有對象都具有這些基本的屬性和方法。
*****
從技術(shù)角度講,ECMA-262中對象的行為不一定適用于JavaScript中的其他對象。瀏覽器環(huán)境中的對象,比如BOM和DOM中的對象,都屬于宿主對象,因為它們是由宿主提供和定義的。ECMA-262不負責定義宿主對象,因此宿主對象可能會也可能不會繼承Object。
### 3.5 操作符
ECMAScript操作符的與眾不同之處在于,它們能夠適用于很多值,例如字符串、數(shù)值、布爾值,甚至對象。不過,在應用于對象時,相應的操作符通常都會調(diào)用對象的valueOf()和(或)toString()方法,以便取得可以操作的值。
#### 3.5.1 一元操作符
只能操作一個值的操作符叫做一元操作符。它們包括:
遞增和遞減操作符:++、--
一元加和一元減操作符:+、-
*****
后置遞增和遞減與前置遞增和遞減有一個非常重要的區(qū)別,即遞增和遞減操作是在包含他們的語句被求值之后才執(zhí)行的。
例:
~~~
var num1 = 2, num2 = 20;
Var num3 = num1-- + num2; //22
Var num4 = num1 + num2: //21
~~~
對單個數(shù)據(jù)類型使用一元加和一元減操作符,該操作符會像Number()轉(zhuǎn)型函數(shù)一樣對這個值執(zhí)行轉(zhuǎn)換。(注:在所有轉(zhuǎn)型函數(shù)中,只有Number()會對Object類型調(diào)用valueOf()和(或)toString()方法進行下一步操作。)。
#### 3.5.3 布爾操作符
***ECMAScript程序的賦值語句經(jīng)常會利用邏輯或的特性,避免為變量賦null或undefined值***:
`var myObject = preferredObject || backupObject;`
在邏輯與中,如果第一個運算數(shù)為假,那么返回第一個運算數(shù),否則返回第二個運算數(shù)。
在邏輯或中,如果第一個運算數(shù)為真,那么返回第一個運算數(shù),否則返回第二個運算數(shù)。
***邏輯與、邏輯或都只會進行布爾測試,而不會真正地對操作數(shù)進行轉(zhuǎn)型轉(zhuǎn)換*!**
#### 3.5.4 乘性操作符
3個乘性操作符:乘法、除法和求模,在操作數(shù)為非數(shù)值的情況下同樣會執(zhí)行自動的Number()類型轉(zhuǎn)換。
#### 3.5.5 加性操作符
如果應用加法操作符(+)的數(shù)據(jù)中存在字符串,則都會轉(zhuǎn)換成字符串進行拼接;如果應用減法操作符(-)則全部轉(zhuǎn)換為數(shù)值進行運算。
*****
**總的來說,算數(shù)操作符中,除了加法操作符會在操作數(shù)存在字符串的情況下進行String()的類型轉(zhuǎn)換,其他操作符在遇到非數(shù)值類型時,都會進行Number()轉(zhuǎn)換。**
#### 3.5.6 關系操作符
關系操作符包括<、>、<=、>= 4個。如果兩個操作數(shù)都是字符串,則會比較兩個字符串對應的字符編碼值。其他情況都會進行Number()轉(zhuǎn)換。
#### 3.5.7 相等操作符
相等(==)和不等(!=)操作符優(yōu)先進行Number()類型轉(zhuǎn)換再比較。另外還要遵循下列規(guī)則:
- null和undefined是相等的;
- 要比較相等性之前,不能將null和undefined轉(zhuǎn)換成其他值。
- 如果有一個操作數(shù)是NaN,則相等操作符返回false,而不相等操作符返回true。即使兩個數(shù)都是NaN,相等操作符也返回false。
- 如果兩個操作數(shù)是對象,則比較它們是不是同一個對象。如果兩個操作數(shù)都指向同一個對象,則相等操作符返回true,否則返回false。
***在實際編程中,為了保持代碼中數(shù)據(jù)類型的完整性,推薦使用全等和全不等操作符。***
#### 3.5.8 條件操作符
條件操作符(也稱三元操作符)的語法形式如下:
`var variable = boolean_expression ? true_value : false_value;`
問號前面的表達式將進行布爾測試,相當于
```
var variable;
if (boolean_expression) {
variable = true_value;
} else {
Varable = false_value;
}
```
## 操作符類型轉(zhuǎn)換總結(jié):
- 算數(shù)操作符(++、--、一元加操作符+、一元減操作符-、加法操作符+、減法操作符-、*、/、%):除了加法操作符(+)會在其中一個操作數(shù)是字符串的情況下對其他類型操作數(shù)進行String()類型轉(zhuǎn)換,其他操作符在遇到非數(shù)值類型是,都會進行Number()轉(zhuǎn)換。
- 布爾操作符(!、||、&&):邏輯非(!)會進行Boolean()轉(zhuǎn)換,邏輯與(&&)和邏輯或(||)不進行類型轉(zhuǎn)換。
- 關系操作符(<、>、<=、>=):如果兩個操作數(shù)都是字符串,則會比較兩個字符串對應的字符編碼值。其他情況都會進行Number()轉(zhuǎn)換,再返回布爾值。
- 相等操作符(==、!=、===、!==):相等(==)和不等(!=)操作符優(yōu)先進行Number()類型轉(zhuǎn)換再比較。另外還要遵循特殊的規(guī)則。全等(===)和全不等(!==)操作符不進行類型轉(zhuǎn)換。
### 3.6 語句
#### 3.6.1 if語句
***多嘗試使用if...else if...else語句以精簡代碼,當然最佳實踐是使用switch。***
#### 3.6.5 for語句
for-in語句是一種精確的迭代語句,可以用來枚舉對象的屬性。以下是for-in語句的語法:
`for (property in expression) statement`
示例:
~~~
for (var propName in window) {
document.write(propName);
}
~~~
在這個例子中,我們使用for-in語句循環(huán)來顯示了BOM中window對象的所有屬性。每次執(zhí)行循環(huán),都會將window對象中存在的一個屬性名賦值給變量propName。這個過程會一直持續(xù)到對象中的所有屬性都被枚舉一遍為止。與for語句類似,這里控制語句中的var操作符也不是必須的,但是為了保證使用局部變量,我們推薦上面例子中的這種做法。
*****
如果表示要迭代的對象的變量值為null或undefined,for-in語句在ES5之前的版本會拋出錯誤。建議在使用for-in循環(huán)之前,先檢測確認該對象的值不是null或undefined。
#### 3.6.9 switch語句
***switch語句可以合并使用***,例:
~~~
Switch (i) {
case 25:
case 35:
alert(“25或35”);
break;
case 45:
alert(“45”);
break;
default:
alert(“other”);
}
~~~
這其實也相當于
~~~
if (i == 25 || i==35) {
alert(“25或35”);
}
~~~
### 3.7 函數(shù)
#### 3.7.1 理解參數(shù)
ECMAScript中的參數(shù)在內(nèi)部是用一個數(shù)組來表示的,在函數(shù)體內(nèi)可以通過arguments對象來訪問這個參數(shù)數(shù)組,從而獲取出傳遞給函數(shù)的每一個參數(shù)。
*****
其實,arguments對象只是與數(shù)組類似(它并不是Array的實例),因為***可以使用方括號語法訪問它的每一個元素,使用length屬性來確定傳遞進來多少個參數(shù)。開發(fā)人員可以利用length屬性讓函數(shù)能夠接收任意個參數(shù)并分別實現(xiàn)適當?shù)墓δ?**。
*****
關于arguments的行為,還有一點比較有意思。那就是它的值永遠與對應命名參數(shù)的值保持同步。沒有傳遞值的命名參數(shù)將被自動賦予undefined值。
