本章內容
- 語法
- 數據類型
- 流控制語句
- 理解函數
3.1 語法
3.1.1 區分大小寫
區分大小寫
3.1.2 標識符
- 第一個字符必須是一個字母、下劃線(_)或1一個美元符號($);
- 其他字符可以是字母、下劃線、美元符號或數字。
按照慣例,ECMAScript 標識符采用駝峰大小寫格式。
3.1.3 注釋
// 單行注釋
/*
這是一個多行(塊級)注釋
*/
3.1.4 嚴格模式
"use strict";
function doSomething () {
"use strict";
//函數體
}
3.1.5 語句
ECMAScript中的語句以一個分號結尾。
var sum = a + b
var diff = a - b;
雖然語句結尾的分號不是必需的,但我們建議任何時候都不要省略它。
最佳實踐是始終在控制語句中使用代碼塊
if (test) {
alert(test);
}
3.2 關鍵字和保留字
3.3 變量
var message;
var message = "hi";
var message = "hi";
message = 100; //有效,但不推薦
function test () {
var message = "hi"; // 局部變量
}
test();
alert(message); // 錯誤!
3.4 數據類型
ECMAScript 中有5種基本數據類型:Undefined
、Null
、Boolean
、Number
和String
。還有一種復雜數據類型——Object
。
3.4.1 typeof 操作符
對于一個值使用typeof
操作符可能返回下列某個字符串:
- "undefined"——如果這個值未定義
- "boolean"——如果這個值是布爾值
- "string"——如果這個值是字符串
- "number"——如果這個值是數值
- “object”——如果這個值是對象或null
- "function"——如果這個值是函數
var message = "some string";
alert(typeof message); // "string"
alert(typeof(message)); // "string"
alert(typeof 95); // "number"
注意,typeof
是一個操作符而不是函數,因此例子中的圓括號不是必需的。
3.4.2 Undefined 類型
Undefined
類型只有一個值,即特殊的 undefined
。
var message;
alert(message == undefined); //true
var message;
// 下面這個變量未聲明
// var age
alert(message); // "undefined"
alert(age); // 產生錯誤
var message
// var age
alert(typeof message); // "undefined"
alert(typeof age); // "undefined"
3.4.3 Null 類型
只有一個值null
。
var car = null;
alert(typeof car); // "object"
如果定義的變量準備在將來用于保存對象,那么最好將該變量初始化為null
而不是其他值。
if (car != null) {
// 對 car 對象執行某些操作
}
實際上,undefined
值是派生自null
值的。
alert(null == undefined); //true
沒有必要把一個變量的值顯式地設置為undefined
。
只要意在保存對象的變量還沒有真正保持隊形,就應該明確保存null
值。
3.4.4 Boolean 類型
var found = true;
var lost = false;
True
和False
都不是Boolean
值,只是標識符。
ECMAScript中所有類型的值都有與這兩個Boolean
值等價的值,可以調用轉型函數Boolean()
。
var message = "Hello world!";
var messageAsBoolean = Boolean(message);
數據類型 | 轉換為true的值 | 轉換為false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | 空字符串 |
Number | 任何非零數字值 | 0和NaN |
Object | 任何對象 | null |
Undefined | n/a (不適用) | undefined |
var message = "Hello world";
if (message) {
alert("Value is true");
}
3.4.5 Number 類型
var intNum = 55;
八進制字面值的第一位必須是0
。八進制字面量在嚴格模式下是無效的。
var octalNum1 = 070; //八進制的56
var octalNum2 = 079;
var octalNum3 = 08; //無效的八進制數值——解析為8
十六進制字面值的前兩位必須是 0x
。
var hexNum1 = 0xA; //十六進制的10
var hexNum2 = 0xlf; //十六進制的31
在進行算術計算時,所有以八進制和十六進制表示的數值最終都將被轉換成十進制數值。
1.浮點數值
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; //有效,但不推薦
var floatNum1 = 1.; //小數點后面沒有數字——解析為1
var floatNum2 = 10.0; //整數——解析為10
var floatNum = 3.125e7; //等于31250000
在默認情況下,ECMAScript會將那些小數點后面帶有6個零以上的浮點數值轉換為以e表示法表示的數值(0.0000003會被轉換成3e-7)。
浮點數值的最高精度是17位小數,但在進行算術計算時其精確度遠遠不如整數。例如,0.1加0.2結果不是0.3,而是0.30000000000000004。
2.數值范圍
計算結果得到一個超出JavaScript數值范圍的值,那么這個數值將被自動轉換成特殊的Infinity
值。負數會被轉換成-Infinity
,正數會被轉換成Infinity
。
var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result)); //false
3.NaN
這個數值用于表示一個本來要返回數值的操作數未返回數值的情況(這樣就不會拋出錯誤了)。在ECMAScript中,任何數值除以0會返回NaN
,不會影響其他代碼的執行。
任何涉及NaN
的操作都會返回NaN
,這個特點在多步計算中有可能導致問題。
NaN
與任何值都不想等,包括NaN
本身。
alert(NaN == NaN); //false
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false
alert(isNaN("10")); //false
alert(isNaN("blue")); //true(不能轉換成數值)
alert(isNaN(true)); //false(可以被轉換成數值1)
4.數值轉換
有3個函數可以把非數值轉換為數值:Number()
、parseInt()
和parseFloat()
。
Number()
函數的轉換規則如下。
- 如果是
Boolean
值,true
和false
將被轉換為1
和0
。 - 如果是數字值,只是簡單的傳入和返回。
- 如果是
null
值,返回0
。 - 如果是
undefined
,返回NaN
。 - 如果是字符串,遵循下列規則:
如果是字符串中只包含數字,則將其轉換為十進制數值;(忽略前導零)
如果字符串中包含有效的浮點格式,則將其轉換為對應的浮點數值;(忽略前導0)
如果字符串中包含有效的十六進制格式,則將其轉換為相同大小的十進制整數值;
如果字符串是空的,則將其轉換為0
;
如果字符串中包含除上述格式之外的字符,則將其轉換為NaN
。 - 如果是對象,則調用對象的
valueOf()
方法,然后依照前面的規則轉換返回的值。如果轉換的結果是NaN
,則調用對象的toString()
,然后再次依照前面的規則轉換返回的字符串值。
var num1 = Number("Hello world!"); //NaN
var num2 = Number(""); //0
var num3 = Number("000011"); //11
var num4 = Number(true); //1
一元操作符的操作與Number()函數相同
parseInt()
函數在轉換字符串時,更多的是看其是否符合數值模式。它會忽略字符串前面的空格,直至找到第一個非空格字符。如果第一個字符不是數字字符或者負號,會返回NaN
;如果第一個字符是數字字符,會繼續解析,知道解析完所有后需字符或遇到一個非數字字符。
var num1 = parseInt("1234blue1213"); //1234
var num2 = parseInt(""); //NaN
var num3 = parseInt("0xA"); //10 (十六進制數)
var num4 = parseInt(22.5); //22
var num = parseInt("0xAF", 16); //175
var num = parseInt("AF", 16); //175
var num2 = parseInt("AF"); //NaN
parseFloat
也是從第一個字符開始解析每個字符。一直解析到字符串末尾,或者解析到遇見一個無效的浮點數字字符為止。
始終都會忽略前導的零。只解析十進制值。
var num1 = parseFloat("1234blue"); //1234
var num2 = parseFloat("0xA"); //0
var num3 = parseFloat("22.5"); //22.5
var num4 = parseFloat("22.34.5"); //22.34
var num5 = parseFloat("0908.5"); //908.5
var num6 = parseFloat("3.12e7"); //31250000
3.4.6 String 類型
var firstName = "Nicholas";
var lastName = 'Zakas';
1.字符字面量
String
數據類型包含一些特殊的字符字面量,也叫轉義序列。
2.字符串的特點
要改變某個變量保存的字符串,首先要銷毀原來的字符串,然后再用另一個包含新值的字符串填充該變量。
var lang = "Java";
lang =lang + "Script";
3.轉換為字符串
把一個值轉換為一個字符串有兩種方式。第一種是使用幾乎每個值都有的toString()
方法。這個方法唯一要做的就是返回相應值得字符串表現。
var age =11;
var ageAsString = age.toString(); //字符串“11”
var found = true;
var foundAsString = found.toString(); //字符串”true“
數值、布爾值、對象和字符串值都有toString()
方法。但null
和undefined
值沒有這個方法。
toString()
可以輸出以二進制、八進制、十六進制,乃至其他任意有效進制格式標識的字符串值。
var num = 10;
alert (num.toString()); //"10"
alert (num.toString(2)); //"1010"
alert (num.toString(8)); //"12"
alert (num.toString(10)); //"10"
alert (num.toString(10)); //"a"
在不知道要轉換的值是不是null
和undefined
的情況下,還可以使用轉型函數String()
,這個函數能將任何類型的值轉換為字符串。
- 如果值有
toString()
方法,則調用該方法(沒有參數)并返回相應的結果; - 如果值是
null
,則返回”null“; - 如果值是
undefined
,則返回”undefined“。
3.4.7 Object 類型
ECMAScript中的對象其實就是一組數據和功能的集合。
var o = new Object();
var o = new Object;//有效,但不推薦省略圓括號
Object
的每個實例都具有下列屬性和方法。
-
Constructor
:保存著用于創建當前對象的函數。對于前面的例子而言,構造函數就是Object()
。 -
hasOwnProperty(propertyName)
:用于檢查給定的屬性在當前對象實例中是否存在。其中,作為參數的屬性名必須以字符串形式指定。 -
isPrototypeOf(object)
:用于檢查傳入的對象是否是另一個對象的原型。 -
propertyIsEnumerable(propertyName)
:用于檢查給定的屬性是否能夠使用for-in
語句來枚舉。作為參數的屬性名必須以字符串形式指定。 -
toLocaleString()
:返回對象的字符串表示,該字符串與執行環境的地區對應。 -
toString()
:返回對象的字符串表示。 -
valueOf()
:返回對象的字符串、數值或布爾值表示。通常與toString()
方法的返回值相同。
由于在ECMAScript中Object
是所有對象的基礎,因此所有對象都具有這些基本的屬性和方法。
3.5 操作符
ECMAScript 操作符的與眾不同之處在于,它們能夠適用于很多值,例如字符串、數字值、布爾值,甚至對象。在應用于對象時,相應的操作符通常都會調用對象的valueOf()
和(或)toString()
方法,以便取的可以操作的值。
3.5.1 一元操作符
1.遞增和遞減操作符
var age = 29;
++age;
var age = 29;
--age;
執行前置遞增和遞減操作時,變量的值都是在語句被求值以前改變的。
var age = 29;
var anotherAge = --age + 2;
alert(age); //輸出28
alert(anotherAge); //輸出30
后置型遞增和遞減操作是在包含它們的語句被求值之后才執行的。
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; //等于22
var num4 = num1 + num2; //等于21
在應用于不同的值時,遞增和遞減操作符遵循下列規則。
- 在應用與一個包含有效數字字符的字符串時,先將其轉換為數字值,在執行加減1的操作。字符串變量變成數值變量。
- 在應用于一個不包含有效數字字符的字符串時,將變量的值設置為
NaN
。字符串變量變成數值變量。 - 在應用于布爾值
false
時,先將其轉換為0再執行加減1的操作。布爾值變量變成數值變量。 - 在應用于布爾值
true
時,先將其轉換為1在執行加減1的操作。布爾值變量變成數值變量。 - 在應用于浮點數值時,執行加減1的操作。
- 在應用于對象時,先調用對象的
valueOf()
方法以取得一個可供操作的值。然后對該值應用前述規則。如果結果是NaN
,則在調用toString()
方法后再應用前述規則。對象變量變成數值變量。
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1++; //3
s2++; //NaN
b++; //1
f--; //0.10000000000000009
o--; //-2
2.一元加和減操作符
一元操作符以一個加號表示,放在數值前面,對數值不會產生任何影響。
var num = 25;
num = +num; //25
不過,在對非數值應用一元加操作符時,該操作符會像Number()
轉型函數一樣對這個值執行轉換。
var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = +s1; //1
s2 = +s2; //1.1
s3 = +s3; //NaN
b = +b; //0
f = +f; //1.1
o = +o; //-1
一元減操作符主要用于表示負數。
var num = 25;
num = -num; //-25
應用于飛數值時,一元減操作符遵循與一元加操作符相同的規則,最后再將得到的數值轉換為負數。
3.5.2 位操作符
在 ECMAScript中,當對數值應用位操作符時,后臺會發生如下轉換過程:64位的數值被轉換成32位數值,然后執行位操作,最后再將32位的結果轉換回64位數值。這個轉換過程導致了一個嚴重的副效應,即在對特殊的NaN
和Infinity
值應用位操作時,這兩個值都會被當成0來處理。
如果對非數值應用位操作符,會先使用Number()
函數將該值轉換為一個數值,然后再應用位操作。得到的結果將是一個數值。
1.按位非 (NOT)
var num1 = 25; //二進制
var num2 = ~num1; //二進制
alert(num2); //-26
這也驗證了按位非操作的本質:操作數的負值減1。
2.按位與(AND)
從本質上講,按位與操作就是將兩個數值的每一位對齊,然后根據下表中的規則,對相同位置上的兩個數執行AND操作:
第一個數值的位 | 第二個數值的位 | 結果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
var result = 25 & 3;
alert(result); // 1
3.按位或 (OR)
按位或操作遵循下面這個真值表。
第一個數值的位 | 第二個數值的位 | 結果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
var result = 25 | 3;
alert(result); //27
4.按位異或 (XOR)
按位異或操作符由一個插入符號(^)表示,也有倆操作數。以下是按位異或的真值表。
第一個數值的位 | 第二個數值的位 | 結果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
var result = 25 ^ 3;
alert (result); //26
5.左移
左移操作符由兩個小于號(<<)表示,這個操作符會將數值的所有位向左移動指定的位數。
var oldValue = 2; //等于二進制的10
var newValue = oldValue << 5; //等于二進制的1000000,十進制的64
左移操作會以0來填充這些空位,以便得到的結果是一個完整的32位二進制數。
注意,左移不會影響操作數的符號位。換句話說,如果將-2向左移動5位,結果將是-64,而非64。
6.有符號的右移
有符號的右移操作符由兩個大于號(>>)表示,這個操作符會將數值向右移動,但保留符號位。
var oldValue = 64; //等于二進制的1000000
var newValue = oldValue >> 5; //等于二進制的10,即十進制的2
7.無符號右移
無符號右移操作符由3個大于號(>>>)表示。這個操作符會將數值的所有32位都向右移動。對正數來說,無符號右移結果與有符號右移相同。
var oldValue = 64;
var newValue = oldValue >>> 5; //等于二進制的10,即十進制的2
對負數來說,無符號右移是以0來填充空位,不會保留符號位的值。
var oldValue = -64;
var newValue = oldValue >>> 5; //等于十進制的134217726
3.5.3 布爾操作符
布爾操作符一共有3個:非(NOT)、與(AND)和或(OR)。
1.邏輯非
邏輯非操作符由一個嘆號(!)表示,可以應用于ECMAScript中的任何值。邏輯非操作符首先會將它的操作數轉換為一個布爾值,然后再對其求反。邏輯非操作符遵循下列規則:
- 如果操作數是一個對象,返回
fasle
; - 如果操作數是一個空字符串,返回
true
; - 如果操作數是一個非空字符串,返回
false
; - 如果操作數是數值0,返回
true
; - 如果操作數是任意非0數值(包括Infinity),返回
false
; - 如果操作數是
null
,返回true
; - 如果操作數是
NaN
,返回true
; - 如果操作數是
undefined
,返回true
。
alert(!false); //true
alert(!"blue"); //false
alert(!0); //true
alert(!NaN); //true
alert(!""); //true
alert(!12345); //false
邏輯非操作符也可以用于將一個值轉換為與其對應的布爾值。而同時使用兩個邏輯非操作符,實際上就會模擬Boolean()
轉型函數的行為。
alert(!!"blue"); //true
alert(!!0); //false
alert(!!NaN); //false
alert(!!""); //false
alert(!!12345); //true
2.邏輯與
邏輯與操作符由兩個和號(&&)表示,有兩個操作數,如下面的例子所示:
var result = true && false;
邏輯與的真值表如下:
第一個操作數 | 第一個操作數 | 結果 |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
邏輯與操作可以應用于任何類型的操作數,而不僅僅是布爾值。在有一個操作數不是布爾值的情況下,邏輯與操作就不一定返回布爾值;此時,他遵循下列規則:
- 如果第一個操作數是對象,則返回第二個操作數;
- 如果第二個操作數是對象,則只有在第一個操作數的求值結果為
true
的情況下才會返回該對象; - 如果兩個操作數都是對象, 則返回第二個操作數;
- 如果有一個操作數是
NaN
,則返回NaN
; - 如果有一個操作數是
undefined
,則返回undefined
。
邏輯與操作術語短路操作,即如果第一個操作數能夠決定結果,那么就不會再對第二個操作數求值。如果第一個操作數是false
, 則無論第二個操作數是什么值,結果都不會是true
了。
var found = true;
var result = (found && someUndefinedVariable); //這里會發生錯誤
alert(result); //這一行不會執行
var found = false;
var result = (found && someUndefinedVariable); //不會發生錯誤
alert(result); //會執行("false")
3.邏輯或
邏輯或操作符由兩個豎線符號(||)表示,由兩個操作數。
var result = true || false;
邏輯或的真值表如下:
第一個操作數 | 第二個操作數 | 結果 |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
如果有一個操作數不是布爾值,邏輯或也不一定返回布爾值;此時,它遵循下列規則:
- 如果第一個操作數是對象,則返回第一個操作數;
- 如果第一個操作數的求值結果為
false
,則返回第二個操作數; - 如果兩個操作數都是對象,則返回第一個操作數;
- 如果兩個操作數都是
null
,則返回null
; - 如果兩個操作數都是
NaN
,則返回NaN
; - 如果兩個操作數都是
undefined
,則返回undefined
。
邏輯或操作符也是短路操作符。也就是說,如果第一個操作數的求值結果為true
,就不會對第二個操作數求值了。
var found = true;
var result = (found || someUndefinedVariable); //不會發生錯誤
alert(result); //會執行 ("true")
var found = false;
var result = (found || someUndefinedVariable); //這里會發生錯誤
alert(result); //這一行不會執行
我們可以利用邏輯或的這一行為來避免為變量賦null
或undefined
值。例如:
var myObject = preferredObject || backupObject;
3.5.4 乘性操作符
ECMAScript定義了3個乘性操作符:乘法、除法和求模。如果參與乘法計算的某個操作數不是數值,后臺會先使用Number()
轉型函數將其轉換為數值。也就是說,空字符串將被當作0,布爾值true
將被當作1。
1.乘法
乘法操作符由一個星號(*)表示,用于計算兩個數值的乘積。
var result = 34 * 56;
在處理特殊值的情況下,乘法操作符遵循下列特殊的規則:
- 如果操作數都是數值,執行常規的乘法計算。如果乘積超過了ECMAScript數值的表示范圍,則返回
Infinity
或-Infinity
; - 如果有一個操作數是
NaN
,則結果是NaN
; - 如果是
Infinity
與0相乘,則結果是NaN
; - 如果是
Infinity
與非0數值相乘,則結果是Infinity
或-Infinity
,取決于有符號操作數的符號; - 如果有一個操作數不是數值,則在后臺調用
Number()
將其轉換為數值,然后再應用上面的規則。
2.除法
除法操作符由一個斜線符號(/)表示,執行第二個操作數除第一個操作數的計算,如下面的例子所示:
var result = 66 / 11;
規則如下:
- 如果操作數都是數值,執行常規的除法計算。如果商超過了ECMAScript數值的表示范圍,則返回
Infinity
或-Infinity
; - 如果有一個操作數是
NaN
,則結果是NaN
; - 如果是
Infinity
被Infinity
除,則結果是NaN
; - 如果是零被零出,則結果是
NaN
; - 如果是非零的有限數被零除,則結果是
Infinity
或-Infinity
; - 如果是
Infinity
被任何非零數值除,則結果是Infinity
或-Infinity
; - 如果有一個操作數不是數值,則在后臺調用
Number()
將其轉換為數值,然后在應用上面的規則。
3.求模
求模(余數)操作符由一個百分號(%)表示,用法如下:
var result = 26 % 5; //等于1
求模操作符會遵循下列特殊規則來處理特殊的值:
- 如果操作數都是數值,執行常規的除法計算,返回除得的余數;
- 如果被除數是無窮大值而除數是有限大的數值,則結果是
NaN
; - 如果被除數是有限大的數值而除數是零,則結果是
NaN
; - 如果是
Infinity
被Infinity
除,則結果是被除數
; - 如果被除數是有限大的數值而除數是無窮大的數值,則結果是被除數;
- 如果被除數是零,則結果是零;
- 如果有一個操作數不是數值,則在后臺調用
Number()
將其轉化為數值,然后在應用上面的規則。
3.5.5 加性操作符
在ECMAScript中,這兩個操作符有一系列的特殊行為。
1.加法
var result = 1 + 2;
如果兩個操作符都是數值,執行常規的加法計算,然后根據下列規則返回結果:
- 如果有一個操作數是
NaN
,則結果是NaN
; - 如果是
Infinity
加Infinity
,則結果是Infinity
; - 如果是
-Infinity
加-Infinity
,則結果是-Infinity
; - 如果是+0加+0,則結果是+0;
- 如果是-0加-0,則結果是-0;
- 如果是+0加-0,則結果是+0;
不過,如果有一個操作數是字符串,那么就要應用如下規則:
- 如果兩個操作數都是字符串,則將第二個操作數與第一個操作數拼接起來;
- 如果只有一個操作數是字符串,則將另一個操作數轉換為字符串,然后再將兩個字符串拼接起來。
如果有一個操作數是對象、數值或布爾值,則調用它們的toString()
方法取得相應的字符串值,然后再應用前面關于字符串的規則。對于undefined
和null
,則分別調用String()
函數并取得字符串"undefined"和"null"。
var result1 = 5 + 5; //連個數值相加
alert(result1); //10
var result2 = 5 + "5"; //一個數值和一個字符串相加
alert(result2); //"55"
var num1 =5;
var num2 =10;
var message = "The sum of 5 and 10 is" + num1 + num2;
alert(message); //"The sum of 5 and 10 is 510"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is" + (num1 + num2);
alert(message); //"The sum of 5 and 10 is 15"
2.減法
var result = 2 - 1;
同樣需要遵循一些特殊規則,如下所示:
- 如果兩個操作符都是數值,則執行常規的算術減法操作并返回結果;
- 如果有一個操作數是
NaN
,則結果是NaN
; - 如果是
Infinity
減Infinity
,則結果是NaN
; - 如果是
-Infinity
減-Infinity
,則結果是NaN
; - 如果是
Infinity
減-Infinity
,則結果是Infinity
; - 如果是
-Infinity
減Infinity
,則結果是-Infinity
; - 如果是+0減+0,則結果是+0;
- 如果是+0減-0,則結果是-0;
- 如果是-0減-0,則結果是+0;
- 如果有一個操作數是字符串、布爾值、
null
或undefined
,則先在后臺調用Number()
函數將其轉換為數值,然后再根據前面的規則執行減法計算。如果轉換的結果是NaN
,則減法的結果就是NaN
; - 如果有一個操作符是對象,則調用對象的
valueOf()
方法以取得表示該對象的數值。如果得到的值是NaN
,則減法的結果就是NaN
。如果對象沒有valueOf()
方法,則調用其toString()
方法并將得到的字符串轉換為數值。
var result1 = 5 - true; //4
var result2 = NaN - 1; //NaN
var result3 = 5 - 3; //2
var result4 = 5 - ""; //5
var result5 = 5 - "2"; //3
var result6 = 5 - null; //5
3.5.6 關系操作符
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)這幾個關系操作符用于對兩個值進行比較,這幾個操作符都返回一個布爾值。
var result1 = 5 > 3; //true
var result2 = 5 < 3; //false
當關系操作符的操作數使用了非數值時,也要進行數據轉換或完成某些奇怪的操作。
- 如果連個操作數都是數值,則執行數值比較。
- 如果兩個操作數都是字符串,則比較兩個字符串對應的字符編碼值。
- 如果一個操作數是數值,則將一個操作數轉換為一個數值,然偶執行數值比較。
- 如果一個操作數是對象,則調用這個對象的
valueOf()
方法,用得到的結果按照前面的規則執行比較。如果對象沒有valueOf()
方法,則調用toString
方法,并用得到的結果根據前面的規則執行比較。 - 如果一個操作數是布爾值,則先將其轉換為數值,然后在執行比較。
在使用關系操作符比較兩個字符串時,會執行一種奇怪的操作。很多人都會認為,在比較字符串值時,小于的意思是“在字母表中的位置靠前”,而大于則意味著“在字母表中的位置靠后”,但實際上完全不是那么回事。在比較字符串時,實際比較的是兩個字符串中對應位置的每個字符的字符編碼值。經過這么一番比較后,再返回一個布爾值。由于大寫字母的字符編碼全部小于小寫字母的字符編碼,因此我們就會看到如下所示的奇怪現象:
var result = "Brick" < "alpahabet"; //true
要真正按照字母表順序比較字符串,就必須把兩個操作數轉換為相同的大小寫形式,然后在執行比較,如下所示:
var result = "Brick.toLowerCase()" < "alphabet".toLowerCase(); //false
var result = "23" < "3"; //true
var result = "23" < 3; //false
var result = "a" < 3; //false,因為“a”被轉換成了NaN
var result1 = NaN < 3; //false
var result2 = NaN >= 3; //false
按照常理,如果一個值不小于另一個值,則一定是大于或等于那個值。然而,在與NaN
進行比較時,這兩個比較操作的結果都返回了fasle
。
3.5.7 相等操作符
在比較字符串、數值和布爾值的的相等性時,問題還比較簡單。但在涉及到對象的比較時,問題就變得復雜了。最后,ECMAScript的解決方案就是提供兩組操作符:相等和不相等——先轉換在比較,全等和不全等——僅比較而不轉換。
1.相等和不相等
會先轉換操作數,然后再比較它們的相等性。在轉換不同的數據類型時,相等和不相等操作符遵循下列基本規則:
- 如果有一個操作數是布爾值,則在比較相等性之前先將其轉換為數值——
false
轉換為0,而true
轉換為1; - 如果一個操作數是字符串,另一個操作數是數值,在比較相等性之前先將字符串轉換為數值;
- 如果一個操作數是對象,另一個操作數不是,則調用對象的
valueOf()
方法,用得到的基本類型值按照前面的規則進行比較;
這兩個操作符在進行比較時則要遵循下列規則。
-
null
和undefined
是相等的。 - 要比較相等性之前,不能將
null
和undefined
轉換成其他任何值。 - 如果有一個操作數是
NaN
,則相等操作符返回false
,而不相等操作符返回true
。重要提示:即使兩個操作數都是NaN
,相等操作符也返回false
;按照規則,NaN
不等于NaN
。 - 如果兩個操作數都是對象,則比較它們是不是同一個對象。如果兩個操作數都指向同一個對象,則相等操作符返回
true
;否則,返回false
。
下表列出了一些特殊情況及比較結果:
表達式 | 值 |
---|---|
null == undefined | true |
"NaN" == NaN | false |
5 == NaN | false |
NaN == NaN | false |
NaN != NaN | true |
false == 0 | true |
true == 1 | true |
true == 2 | false |
undefined == 0 | false |
null == 0 | false |
"5" == 5 | true |
2.全等和不全等
只在兩個操作數未經轉換就相等的情況下返回true
。
var result1 = ("55" == 55); //true,因為轉換后相等
var result2 = ("55" === 55); //false,因為不同的數據類型不相等
var result1 = ("55" != 55); //false,因為轉換后相等
var result2 = ("55" !== 55); //true,因為不同的數據類型不相等
3.5.8 條件操作符
variable = boolean_expression ? true_value : false_value;
var max = (num1 > num2) ? num1: num2;
3.5.9 賦值操作符
var num = 10;
var num = 10;
num += 10;
每個主要算術操作符(以及個別的其他操作符)都有對應的復合賦值操作符。這些操作符如下所示:
- 乘/賦值 (*=);
- 除/賦值 (/=);
- 模/賦值 (%=);
- 加/賦值 (+=);
- 減/賦值 (-=);
- 左移/賦值 (<<=);
- 有符號右移/賦值 (>>=);
- 無符號右移/賦值 (>>>=)。
3.5.10 逗號操作符
使用逗號操作符可以在一條語句中執行多個操作。
var num1 =1, num2 = 2, num3 = 3;
逗號操作符還可以用于賦值。在用于賦值時,逗號操作符總會返回表達式中的最后一項。
var num = (5, 1, 4, 8, 0); //num的值為0
由于0是表達式中的最后一項,因此num
的值就是0。
3.6 語句
從本質上看,語句定義了ECMAScript中的主要語法,語句通常使用一或多個關鍵字來完成給定任務。
3.6.1 if 語句
if (condition) statement1 else statement2
if (i > 25)
alert("Greater than 25."); //單行語句
esle {
alert("Less than or equal to 25."); //代碼塊中的語句
}
不過,業界普遍推崇的最佳實踐是始終使用代碼塊,即使要執行的只有一行代碼。
另外,也可以把整個if
語句寫在一行代碼中:
if (condition1) statement1 else if (condition2) statement2 else statement3
但我們推薦的做法則是像下面這樣:
if (i > 25) {
alert("Greater than 25.");
} else if (i < 0) {
alert("Less than 0.");
} else {
alert("Between 0 and 25, inclusive.");
}
3.6.2 do-while 語句
do-while
語句是一種后測試循環語句,即只有在循環體中的代碼執行之后,才會測試出口條件。
do {
statement
} while (expression);
var i = 0;
do {
i += 2;
} while (i < 10);
alert(i);
3.6.3 while 語句
while
語句屬于前測試循環語句,也就是說,在循環體內的代碼被執行之前,就會對出口條件求值。
while(expression) statement
var i = 0;
while (i < 10) {
i +=2;
}
3.6.4 for語句
for
語句也是一種前測試循環語句,但它具有在執行循環之前初始化變量和定義循環后要執行的代碼的能力。
for (initialization; expression; post-loop-expression) statement
var count = 10;
for (var i = 0; i < count; i++) {
alert(i);
}
這個for
循環語句與下面的while
語句的功能相同:
var count = 10;
var i = 0;
while (i < count) {
alert(i);
i++;
}
變量初始化可以在外部執行,由于ECMAScript中不存在塊級作用域,因此在循環內部定義的變量也可以在外部訪問到。
此外,for
語句中的初始化表達式、控制表達式和循環后表達式都是可選的。將這兩個表達式全部省略,就會創建一個無限循環。
for (; ;) { //無限循環
doSomething();
}
而只給出控制表達式實際上就把for
循環轉換成了while
循環。
var count = 10;
var i = 0;
for (; i < count; ) {
alert(i);
i++;
}
3.6.5 for-in 語句
for-in
語句是一種精準的迭代語句,可以用來枚舉對象的屬性。
for (property in expression) statement
for (var propName in window) {
document.write(propName);
}
ECMAScript對象的屬性沒有順序。因此,通過for-in
循環輸出的屬性名的順序是不可預測的。
但是,如果表示要迭代的對象的變量值為null
或undefined
,for-in
語句會拋出錯誤。ECMAScript5更正了這一行為;對這種情況不再拋出錯誤,而只是不執行循環體。建議在使用for-in
循環之前,先檢測確認該對象的值不是null
或undefined
。
3.6.6 label語句
使用label
語句可以在代碼中添加標簽,以便將來使用。
label: statement
start: for(var i=0; i < count; i++) {
alert(i);
}
這個例子中定義的start
標簽可以在將來由break
或continue
語句引用。加標簽的語句一般都要與for
語句等循環語句配合使用。
3.6.7 break和continue語句
break
和continue
語句用于在循環中精確控制代碼的執行。其中,break
語句會立即退出循環,強制繼續執行循環后面的語句。而continue
語句雖然也是立即退出循環,但退出循環后會從循環的頂部繼續執行。
var num = 0;
for (var i = 1; i < 10; i++) {
if(i % 5 == 0) {
break;
}
num++;
}
alert(num); //4
var num = 0;
for (var i = 1; i < 10; i++) {
if(i % 5 == 0) {
continue;
}
num++;
}
alert(num); //8
break
和continue
語句都可以與label
語句聯合使用,從而返回代碼中特定的位置。
var num = 0;
outermost:
for (var i = 0; i < 10; i++) {
for(var j = 0; j < 10; j++) {
if(i == 5 && j == 5) {
break outermost;
}
num++;
}
}
alert(num); //55
添加這個標簽的結果將導致break
語句不僅會退出內部的for
語句,而且也會退出外部的for
語句。
3.6.8 with語句
with
語句的作用是將代碼的作用域設置到一個特定的對象中。
with (expression) statement;
定義with
語句的目的主要是為了簡化多次編寫同一個對象的工作。
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
with(location) {
var qs = search.substring(1);
var hostName = host.name;
var url = href;
}
嚴格模式下不允許使用with
語句,否則將視為語法錯誤。
不建議使用with
語句。
3.6.9 switch語句
ECMAScript中switch
語句的語法與其他基于C的語言非常接近。
switch (expression) {
case value: statement
break;
case value: statement
break;
case value: statement
break;
case value: statement
break;
default: statement
}
假如確實需要混合幾種情形,不要忘了在代碼中添加注釋,說明你是有意省略了break
關鍵字。
switch(i) {
case 25:
/*合并兩種情形*/
case 35:
alert("25 or 35");
break;
case 45:
alert("45");
break;
default:
alert("other");
}
可以在switch
語句中使用任何數據類型,無論是字符串,還是對象都沒有問題。。每個case
的值不一定是常量,可以是變量,甚至是表達式。
switch
語句在比較值時使用的是全等操作符,因此不會發生類型轉換。
3.7 函數
ECMAScript中的函數使用function
關鍵字來聲明,后跟一組參數以及函數體。
function functionName(arg0, arg1, ..., argN) {
statements
}
function sayHi(name, message) {
alert("hello " + name + "," + message);
}
實際上,任何函數在任何時候都可以通過return
語句后跟要返回的值來實現返回值。
function sum(num1, num2) {
return num1 + num2;
}
return
語句也可以不帶有任何返回值。在這種情況下,函數在停止執行后將返回undefined
值。這種用法一般用在需要提前停止函數執行而又不需要返回值的情況下。
推薦的做法是要么讓函數始終都返回一個值,要么永遠都不要返回值。
嚴格模式對函數有一些限制:
- 不能把函數命名為
eval
或arguments
; - 不能把參數命名為
eval
或arguments
; - 不能出現兩個命名參數同名的情況。
如果發生以上情況,就會導致語法錯誤,代碼無法執行。
3.7.1 理解函數
在函數體內可以通過arguments
對象來訪問這個參數數組,從而獲取傳遞給函數的每一個參數。
arguments
對象只是與數組類似,因為可以使用方括號語法訪問它的每一個元素,使用length
屬性來確定傳遞進來多少個參數。
function sayHi() {
alert("hello " + arguments[0] + "," + arguments[1]);
}
這個重寫后的函數中不包含命名的參數。這個事實說明:命名的參數只提供便利,但不是必需的。
通過訪問arguments
對象的length
屬性可以獲知有多少個參數傳遞給了函數。
function howManyArgs() {
alert(arguments.length);
}
howManyArgs("string", 45); //2
howManyArgs(); //0
howManyArgs(12); //1
開發人員可以利用這一點讓函數能夠接收任意個參數并分別實現適當的功能。
function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 10);
} else if (arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //20
doAdd(30, 20); //50
另一個與參數相關的重要方面,就是arguments
對象可以與命名參數一起使用。
function doAdd(num1, num2) {
if(arguments.length ==1) {
alert(num1 + 10);
} else if (arguments.length == 2) {
alert(arguments[0] + num2);
}
}
關于arguments
的行為,還有一點比較有意思。那就是它的值永遠與對應命名參數的值保持同步。
function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
每次執行這個函數都會重寫第二個參數,將第二個參數的值修改為10.因為arguments
對象中的值會自動反映到對應的命名參數。它們的內存空間是獨立的,但它們的值會同步。但這種影響是單向的:修改命名參數不會改變arguments
中對應的值。如果只傳入了一個參數,那么為arguments[1]
設置的值不會反應到命名參數中。這是因為arguments
對象的長度是由傳入的參數個數決定的,不是由定義函數時的命名參數的個數決定的。
關于參數還要記住最后一點:沒有傳遞值的命名參數將自動被賦予undefined
值。
嚴格模式中,像前面例子中那樣的賦值會變得無效,即使把arguments[1]
設置為10,num2
的值仍然還是undefined
。其次,重寫arguments
的值會導致語法錯誤。
ECMAScript中的所有參數傳遞的都是值,不可能通過引用傳遞參數。
3.7.2 沒有重載
ECMAScript函數不能像傳統意義上那樣實現重載。
如果在ECMAScript中定義了兩個名字相同的函數,則該名字只屬于后定義的函數。
function addSomeNumber(num) {
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
var result = addSomeNumber(100); //300
3.8 小結
以下簡要總結了ECMAScript中基本的要素。
- ECMAScript中的基本數據類型包括
Undefined
、Null
、Booelan
、Number
和String
。 - 與其他語言不同,ECMAScript沒有為整數和浮點數值分別定義不同的數據類型,
Number
類型可用于表示所有數值。 -
Object
類型,該類型是這門語言中所有對象的基礎類型。 - 嚴格模式為這門語言中容易出錯的地方施加了限制。
- ECMAScript提供了很多與C及其其他類C語言中相同的基本操作符,包括算數操作符、布爾操作符、關系操作符、相等操作符及賦值操作符等。
- 從其他語言借鑒了很多流控制語句,例如
if
語句、for
語句和switch
語句等。
ECMAScript中的函數與其他語言中的函數有諸多不同之處。
- 無須指定函數的返回值。
- 實際上,未指定返回值的函數返回的是一個特殊的
undefined
值。 - ECMAScript中也沒有函數簽名的概念,因為其函數參數是以一個包含零或多個值的數組的形式傳遞的。
- 可以向ECMAScript函數傳遞任意數量的參數,并且可以通過
arguments
對象來訪問這些參數。 - 由于不存在函數簽名的特性,ECMAScript函數不能重載。