在深入學習各種數據結構和算法前,讓我們先大概瞭解一下JavaScript。本節教大家一些相關的基礎知識,有利於學習後面各章。
首先來看在HTML中編寫JavaScript的兩種方式:
<!DOCTYPE html>
<html>
<head>
<meta charset=\"UTF-8\">
</head>
<body>
<script>
alert(\'Hello, World!\');
</script>
</body>
</html>
第一種方式如上面的代碼所示。創建一個HTML文件,把代碼寫進去。在這個例子裡,我們在HTML文件中聲明了script
標籤,然後把JavaScript代碼都寫進這個標籤。
第二種方式,我們需要創建一個JavaScript文件(比如01-HelloWorld.js),在裡面寫入如下代碼:
alert(\'Hello, World!\');
然後,我們的HTML文件看起來如下:
<!DOCTYPE html>
<html>
<head>
<meta charset=\"UTF-8\">
</head>
<body>
<script src=\"01-HelloWorld.js\">
</script>
</body>
</html>
第二個例子展示了如何將一個JavaScript文件引入HTML文件。
這兩個例子,無論執行哪個,輸出都是一樣的。但第二個例子是最佳實踐。
可能你在網上的一些例子裡看到過JavaScript的
include
語句,或者放在head
標籤中的JavaScript代碼。作為最佳實踐,我們會在關閉body
標籤前引入JavaScript代碼。這樣瀏覽器就會在加載腳本之前解析和顯示HTML,有利於提升頁面的性能。
1.3.1 變量
變量保存的數據可以在需要時設置、更新或提取。賦給變量的值都有對應的類型。JavaScript的類型有數字、字符串、布爾值、函數和對象。還有undefined
和null
,以及數組、日期和正則表達式。
儘管JavaScript有多種變量類型,然而不同於C/C++、C#或Java,它並不是一種強類型語言。在強類型語言中,聲明變量時需要指定變量的類型(例如,在Java中聲明一個整型變量,使用
int num = 1;
)。在JavaScript中,我們只需要使用關鍵字var
,而不必指定變量類型。因此,JavaScript不是強類型語言。
下面的例子介紹如何在JavaScript裡使用變量。
var num = 1; //{1}
num = 3; //{2}
var price = 1.5; //{3}
var name = \'Packt\'; //{4}
var trueValue = true; //{5}
var nullVar = null; //{6}
var und; //{7}
在行
{1}
,我們展示了如何聲明一個JavaScript變量(聲明了一個數字類型)。雖然關鍵字var
不是必需的,但最好每次聲明一個新變量時都加上。在行
{2}
,我們更新了已有變量。JavaScript不是強類型語言。這意味著你可以聲明一個變量並初始化成一個數字類型的值,然後把它更新成字符串或者其他類型的值,不過這並不是一個好做法。在行
{3}
,我們又聲明了一個數字類型的變量,不過這次是十進制浮點數。在行{4}
, 聲明了一個字符串;在行{5}
,聲明了一個布爾值;在行{6}
,聲明了一個null
;在行{7}
, 聲明了undefined
變量。null
表示變量沒有值,undefined
表示變量已被聲明,但尚未賦值。看看下面的例子:console.log(\"num: \"+ num); console.log(\"name: \"+ name); console.log(\"trueValue: \"+ trueValue); console.log(\"price: \"+ price); console.log(\"nullVar: \"+ nullVar); console.log(\"und: \"+ und);
如果想看我們聲明的每個變量的值,可以用console.log
來實現,就像上面代碼片段中那樣。
書中示例代碼會使用三種方式輸出JavaScript的值。第一種是
alert
(\'My text here\'
),將輸出到瀏覽器的警示窗口;第二種是console.log
(\'My text here\'
),將把文本輸出到調試工具的Console標籤(谷歌開發者工具或是Firebug,根據你使用的瀏覽器而定);第三種方式是通過document.write
(\'My text here\'
)直接輸出到HTML頁面裡並被瀏覽器呈現。可以選擇你喜歡的方式來調試。
console.log
方法也不止接收參數,除了console.log(\"num: \"+ num)
還可以寫成console.log(\"num: \", num)
。
稍後我們會討論函數和對象。
變量作用域
作用域指在編寫的算法函數中,我們能訪問的變量(在使用時,函數作用域也可以是一個函數)。有本地變量和全局變量兩種。
讓我們看一個例子:
var myVariable = \'global\';
myOtherVariable = \'global\';
function myFunction {
var myVariable = \'local\';
return myVariable;
}
function myOtherFunction {
myOtherVariable = \'local\';
return myOtherVariable;
}
console.log(myVariable); //{1}
console.log(myFunction); //{2}
console.log(myOtherVariable); //{3}
console.log(myOtherFunction); //{4}
console.log(myOtherVariable); //{5}
行
{1}
輸出global
,因為它是一個全局變量。行
{2}
輸出local
,因為myVariable
是在myFunction
函數中聲明的本地變量,所以作用域僅在myFunction
內。行
{3}
輸出global
,因為我們引用了在第二行初始化了的全局變量myOtherVariable
。行
{4}
輸出local
。在myOtherFunction
函數里,因為沒有使用var
關鍵字修飾,所以這裡引用的是全局變量myOtherVariable
並將它賦值為local
。因此,行
{5}
會輸出local
(因為在myOtherFunction
裡修改了myOtherVariable
的值)。
你可能聽其他人提過在JavaScript裡應該盡量少用全局變量,這是對的。通常,代碼質量可以用全局變量和函數的數量來考量(數量越多越糟)。因此,盡可能避免使用全局變量。
1.3.2 操作符
編程語言裡都需要操作符。在JavaScript裡有算數操作符、賦值操作符、比較操作符、邏輯操作符、位操作符、一元操作符和其他操作符。我們來看一下這些操作符:
var num = 0; //{1}
num = num + 2;
num = num * 3;
num = num / 2;
num++;
num--;
num += 1; //{2}
num -= 2;
num *= 3;
num /= 2;
num %= 3;
console.log(\'num == 1 : \' + (num == 1)); // {3}
console.log(\'num === 1 : \' + (num === 1));
console.log(\'num != 1 : \' + (num != 1));
console.log(\'num > 1 : \' + (num > 1));
console.log(\'num < 1 : \' + (num < 1));
console.log(\'num >= 1 : \' + (num >= 1));
console.log(\'num <= 1 : \' + (num <= 1));
console.log(\'true && false : \' + (true && false)); // {4}
console.log(\'true || false : \' + (true || false));
console.log(\'!true : \' + (!true));
在行{1}
,我們用了算數操作符。在下面的表格裡,列出了這些操作符及其描述。
算數操作符
描述
+
加法
-
減法
*
乘法
/
除法
%
取余
++
遞增
--
遞減
在行{2}
,我們使用了賦值操作符,在下面的表格裡,列出了賦值操作符及其描述。
賦值操作符
描述
=
賦值
+=
加/賦值 (x += y) == (x = x + y)
-=
減/賦值 (x -= y) == (x = x - y)
*=
乘/賦值 (x *= y) == (x = x * y)
/=
除/賦值 (x /= y) == (x = x / y)
%=
取余/賦值 (x %= y) == (x = x % y)
在行{3}
,我們使用了比較操作符。在下面的表格裡,列出了比較操作符及其描述。
比較操作符
描述
==
相等
===
全等
!=
不等
>
大於
>=
大於等於
<
小於
<=
小於等於
在行 {4}
,我們使用了邏輯操作符。在下面的表格裡,列出了邏輯操作符及其描述。
邏輯操作符
描述
&&
與
||
或
!
非
JavaScript也支持位操作符,如下所示:
console.log(\'5 & 1:\', (5 & 1));
console.log(\'5 | 1:\', (5 | 1));
console.log(\'~ 5:\', (~5));
console.log(\'5 ^ 1:\', (5 ^ 1));
console.log(\'5 << 1:\', (5 << 1));
console.log(\'5 >> 1:\', (5 >> 1));
下面的表格對位操作符做了更詳細的描述。
位操作符
描述
&
與
|
或
~
非
^
異或
<<
左移
>>
右移
typeof
操作符可以返回變量或表達式的類型。我們看下面的代碼:
console.log(\'typeof num:\', typeof num);
console.log(\'typeof Packt:\', typeof \'Packt\');
console.log(\'typeof true:\', typeof true);
console.log(\'typeof [1,2,3]:\', typeof [1,2,3]);
console.log(\'typeof {name:John}:\', typeof {name:\'John\'});
輸出如下:
typeof num: number
typeof Packt: string
typeof true: boolean
typeof [1,2,3]: object
typeof {name:John}: object
JavaScript還支持delete
操作符,可以刪除對像裡的屬性。看看下面的代碼:
var myObj = {name: \'John\', age: 21};
delete myObj.age;
console.log(myObj); // 輸出對像{name: \"John\"}
這些操作符在後面的算法學習中可能會用到。
1.3.3 真值和假值
在JavaScript中,true和false有些複雜。在大多數編程語言中,布爾值true
和false
僅僅表示true/false。在JavaScript中,如\"Packt\"
這樣的字符串值,也可以看作true
。
下面的表格能幫助我們更好地理解true和false在JavaScript中是如何轉換的。
數值類型
轉換成布爾值
undefined
false
null
false
布爾值
true
是true
,false
是false
數字
+0
、-0
和NaN
都是false
,其他都是true
字符串
如果字符串是空的(長度是0)就是false
,其他都是true
對像
true
我們來看一些代碼,用輸出來驗證上面的總結:
function testTruthy(val){
return val ? console.log(\'truthy\') : console.log(\'falsy\');
}
testTruthy(true); //true
testTruthy(false); //false
testTruthy(new Boolean(false)); //true (對像始終為true)
testTruthy(\'\'); //false
testTruthy(\'Packt\'); //true
testTruthy(new String(\'\')); //true (對像始終為true)
testTruthy(1); //true
testTruthy(-1); //true
testTruthy(NaN); //false
testTruthy(new Number(NaN)); //true (對像始終為true)
testTruthy({}); //true (對像始終為true)
var obj = {name:\'John\'};
testTruthy(obj); //true
testTruthy(obj.name); //true
testTruthy(obj.age); //false (年齡不存在)
1.3.4 相等操作符(==
和===
)
當使用這兩個相等操作符時,可能會引起一些困惑。
使用==時,不同類型的值也可以被看作相等。這樣的結果可能會使那些資深的JavaScript開發者都感到困惑。我們用下面的表格給大家分析一下不同類型的值用相等操作符比較後的結果。
類型(x)
類型(y)
結果
null
undefined
true
undefined
null
true
數字
字符串
x == toNumber(y)
字符串
數字
toNumber(x) == y
布爾值
任何類型
toNumber(x) == y
任何類型
布爾值
x == toNumber(y)
字符串或數字
對像
x == toPrimitive(y)
對像
字符串或數字
toPrimitive(x) == y
如果 x 和 y 是相同類型,JavaScript會比較它們的值或對像值。其他沒有列在這個表格中的情況都會返回false
。
toNumber
和toPrimitive
方法是內部的,並根據以下表格對其進行估值。
toNumber
方法對不同類型返回的結果如下:
值類型
結果
undefined
NaN
null
+0
布爾值
如果是true
,返回1
;如果是false
,返回+0
數字
數字對應的值
字符串
將字符串解析成數字。如果字符串中包含字母,返回NaN
;如果是由數字字符組成的,轉換成數字
對像
Number(toPrimitive(vale))
toPrimitive
方法對不同類型返回的結果如下:
值類型
結果
對像
如果對象的valueOf
方法的結果是原始值,返回原始值。如果對象的toString
方法返回原始值,就返回這個值;其他情況都返回一個錯誤
用例子來驗證一下表格中的結果。首先,我們知道下面的代碼輸出true
(字符串長度大於1):
console.log(\'packt\' ? true : false);
那麼這行代碼的結果呢?
console.log(\'packt\' == true);
輸出是false
,為什麼會這樣呢?
首先,布爾值會被
toNumber
方法轉成數字,因此得到packt == 1
。其次,用
toNumber
轉換字符串值。因為字符串包含有字母,所以會被轉成NaN
,表達式就變成了NaN == 1
,結果就是false
。
那麼這行代碼的結果呢?
console.log(\'packt\' == false);
輸出也是false
。步驟如下所示。
首先,布爾值會被
toNumber
方法轉成數字,因此得到packt == 0
。其次,用
toNumber
轉換字符串值。因為字符串包含有字母,所以會被轉成NaN
,表達式就變成了NaN == 0
,結果就是false
。
那麼===
操作符呢?簡單多了。如果比較的兩個值類型不同,比較的結果就是false
。如果比較的兩個值類型相同,結果會根據下表判斷。
類型(x)
值
結果
數字
x 和 y 數值相同(但不是NaN
)
true
字符串
x 和 y 是相同的字符
true
布爾值
x 和 y 都是true
或false
true
對像
x 和 y 引用同一個對像
true
如果 x 和 y 類型不同,結果就是false
。
我們來看一些例子:
console.log(\'packt\' === true); //false
console.log(\'packt\' === \'packt\'); //true
var person1 = {name:\'John\'};
var person2 = {name:\'John\'};
console.log(person1 === person2); //false,不同的對象