JavaScript的基本概念
任何語言的核心,都必然會描述這門語言最基本的工作原理。而描述的內容通常都要涉及這門語言的語法、操作符、資料型別、內建功能等用於構建複雜解決方案的基本理念。為此,這篇文章主要用來介紹JavaScript
這門語言的基本概念
。
1. 語法
合法的格式與指令的組合規則被稱為一種計算機語言 ,有時被稱作它的語法 ,這和英語教你如何拼寫單詞,和如何使用單詞與標點建立合法的句子差不多是相同的。
1.1 區分大小寫
ECMAScript 中的一切(變數、函式名和操作符)都區分大小寫。
也就是說,test
和Test
,分別表示兩個不同的變數。但函式名不能用typeof
,因為它是一個關鍵字
,但typeOf
則完全可以是一個有效的函式名。
1.2 識別符號
所謂識別符號 ,就是指變數、函式、屬性的名字,或者函式的引數。識別符號有如下規則:
一個識別符號必須以a-z
,A-Z
,$
,或_
開頭。它可以包含任意這些字元外加數字0-9
。
識別符號中的字母也可以包含擴充套件的ASCII
或Unicode
字母字元,但是我們不推薦這樣做。
按照慣例,ECMAScript
標識符采用駝峰大小寫
格式,也就是第一個字母小寫,剩下的每個單詞的首字母大寫,如myFirstClass
。
不能把關鍵字(如,do
、else
、this
、typeof
等)、保留字(如,boolean
、export
、float
、public
等)、true
、false
、和null
用作識別符號。
1.3 註釋
ECMAScript
使用C
風格的註釋,包括單行註釋
和塊級註釋
。
//單行註釋 /* *這是一個多行 *(塊級)註釋 */
1.4 嚴格模式
ES5在語言中加入了一個“strict模式
”,它收緊了一些特定行為的規則,使程式碼符合一組更安全和更合理的指導方針。
堅持strict模式
一般會使你的程式碼對引擎有更強的可優化性。strict模式
對程式碼有很大的好處,你應當在你所有的程式中使用它。
根據你擺放strict模式
註解的位置,你可以為一個單獨的函式,或者是整個一個檔案切換到strict模式
:
function foo() { "use strict"; //這部分程式碼是 strict模式 的 function bar() { //這部分程式碼是 strict模式 的 } } // 這部分程式碼不是 strict模式 的
將它與這個相比:
"use strict"; function foo() { //這部分程式碼是 strict 模式的 function bar() { //這部分程式碼是 strict模式 的 } } // 這部分程式碼是 strict模式 的
使用strict模式
的一個關鍵不同是,它不允許因為省略了var
而進行隱含的自動全域性變數宣告:
function foo() { "use stirct";//開啟 strict模式 a = 1;//缺少 `var` ,ReferenceError } foo();
1.5 語句
在一門計算機語言中,一組單詞,數字,和執行一種具體任何的操作符構成了一個語句 。語句以一個 分號 結尾。
在JavaScript
中,語句可能看起來像下面這樣:
var sum = a + b//即使沒有分號也是有效的語句 --- 不推薦 var diff = a -b;//有效的語句 --- 推薦
雖然語句結尾的分號不是必需的,但我們建議任何時候都不要省略它。因為加上分號可以避免錯誤(如不完整的輸入),開發人員可以放心地通過刪除多餘的空格來壓縮程式碼(如果程式碼沒有分號結尾,容易導致壓縮錯誤)。另外,加上分號可以增進程式碼的效能,因為這樣解析器就不必再花時間推測應該在哪裡插入分號了。
2. 變數
大多數有用的程式都需要在程式執行整個過程中,追蹤由於你的程式所意圖的任務被呼叫的底層不同的操作而發生的值的變化。
要這樣做的最簡單的方法是將一個值賦予一個符號容器(佔位符),稱為 ——變數 ,這個容器中的值可以根據需要不時變化 而得名。
定義變數時要使用var
操作符(注意:var
是一個關鍵字
),後跟變數名
(即一個識別符號
),如下所示:
var message;//該變數可以用來儲存任何值,初始狀態的值為:undefined
有一點必須注意,即用var
操作符定義的變數將成為定義該變數的作用域中的區域性變數
。也就是說,如果在函式中用var
定義了一個變數,那麼這個變數在函式被呼叫後就會被銷燬
,例如:
function test() { var message = 'hello';//區域性變數 } test(); alert(message);//報錯
如果省略var
操作符,從而建立一個全域性變數:
function test() { message = 'hello';//全域性變數 } test(); alert(message);//'hello'
這個例子省略了var
操作符,因而message
就成了全域性變數
。這樣,只要呼叫過一次test()
函式,這個變數就有了定義,就可以在函式外部的任何地方被訪問到。
3. 資料型別
ECMAScript
中有5種簡單資料型別
(也稱為基本資料型別
)即:——Undefined
、Null
、Boolean
、Number
和String
。還有一種複雜資料型別
——Object
。
3.1 typeof 操作符
由於ECMAScript
的變數是鬆散型別
(即可以用來儲存任何型別的資料),因此,JavaScript
提供了一個typeof
操作符,它可以檢查一個值,並告訴你它的型別是什麼:
var a; typeof a;// "undefined" a = "hello world"; typeof a;// "string" a = 42; typeof a;// "number" a = true; typeof a;// "boolean" a = null; typeof a;// "object" -- 特殊值 null 被認為是一個空的物件引用(空物件指標),因此為 "object" a = undefined; typeof a;// "undefined" a = { b: "c" }; typeof a;// "object"
3.2 Undefined型別 和 Null型別
實際上,undefined
值是派生自null
值的,因此ECMA-262
規定對它們的相等性測試要返回true
;
alert( null == undefined );//true
儘管null
和undefined
有這樣的關係,但它們的用途完全不同。無論任何情況下,都沒必要把一個變數的值顯式地設為undefined
,但null
則不然。只要意在儲存物件的變數還沒有真正儲存物件,就應該明確地讓該變數儲存null
值。這樣做不僅體現null
作為空物件指標的慣例,而且有助於進一步區分null
和undefined
。
3.3 Boolean 型別
Boolean
型別是ECMAScript
中使用最多的一種型別,該型別只有兩個字面值:true
和false
。
Truthy 與 Falsy:當一個非boolean
值被強制轉換為一個boolean
時,它是變成true
還是false
。
在JavaScript
中falsy
的明確列表如下:
-
" "
(空字串) -
0
,-0
,NaN
(非法的number
) -
null
,undefined
-
false
任何不在這個falsy
列表中的值都是truthy
。例如:
-
"hello"
-
42
-
true
-
[ ]
,[ 1 , "2" , 3 ]
(陣列) -
{ }
,{ a : 42 }
(物件) -
function foo() { ... }
(函式)
3.4 Number 型別
包括 整數 和 浮點數值
NaN
,即非數值(Not a Number
)是一個特殊的數值,這個數值用於表示一個本來要返回數值的操作屬未返回數值的情況(這樣就不會丟擲錯誤了)。
任何數值除以非數值都會返回NaN
,不會影響其他程式碼的執行。
NaN
有兩個非同尋常的特點:
-
任何涉及
NaN
的操作 (例如 NaN/10)都會返回NaN
; -
NaN
與任何值都不相等,包括NaN
本身。
alert( NaN == NaN )//false
針對NaN
的這兩個特點,ECMAScript
定義了isNaN()
函式。這個函式接受一個引數,該引數可以是任何型別,而函式會幫我們確定這個引數是否“不是數值”
。
isNaN()
在接收到一個值之後,會嘗試將這個值轉換為數值,某些不是數值的值會直接轉換為數值。而任何不能被轉換為數值的值都會導致這個函式返回true
。例如:
alert( isNaN(NaN) );//true alert( isNaN(10) );//false ( 10 是一個數值 ) alert( isNaN("10") );//false (可以被轉換成數值 10) alert( isNaN("blue") );//true ( 不能轉換成數值 ) alert( isNaN(true) );//false ( 可以被轉換成數值 1 )
3.5 String 型別
字串可以由雙引號(" ")
或 單引號( ' )
表示。
例如以下兩種寫法:
var a = 'aa'; var b = "b";
字串的特點:不可變 ,也就是說,字串一旦建立,它們的值就不能改變。
要把某個值轉換為字串,有以下兩種方法:
1.用toString()
方法;
2.用+
號把它與一個字串加在一起。
例如:
var num = 10; alert( num.toString() );//"10" var str = "20" alert( num + str );//"1020"
3.6 Object 型別
ECMAScript
中的物件其實就是一組資料和功能的集合。物件可以通過執行new
操作符後跟要建立的物件型別的名稱來建立。
而建立Object
型別的例項併為其新增屬性
和(或)方法
,就可以建立自定義物件
,如下所示:
var o = new Object()
在ECMAScript
中,Object
型別是所有它的例項的基礎。換句話說,Object
型別所具有的任何屬性和方法也同樣存在於更具體的物件中。
Object
的每個例項都具有下列屬性和方法:
-
constructor
: 儲存著用於建立當前物件的函式。對於前面的例子而言,建構函式(constructor
)就是Object()
; -
hasOwnProperty(propertyName)
: 用於檢查給定的屬性在當前物件例項中(而不是在例項的原型中)是否存在。其中,作為引數的屬性名(propertyName
)必須以字串形式指定(例如:o.hasOwnProperty("name")
);
var o = new Object(); o.name = "lily"; o.hasOwnProperty("name");//true o.hasOwnProperty("age");//false var obj = {a:'aa',b:'bb'}; obj.hasOwnProperty("a");//true obj.hasOwnProperty("c");//false
-
isPrototypeOf(object)
: 用於檢查傳入的物件是否是當前物件的原型 ; -
propertyIsEnumerable(propertyName)
: 用於檢查給定的屬性是否能夠使用for-in
語句來列舉,與hasOwnProperty()
方法一樣,作為引數的屬性名必須以字串形式指定; -
toLocaleString()
: 返回物件的字串表示,該字串與執行環境的地區對應; -
toString()
: 返回物件的字串表示; -
valueOf()
: 返回物件的字串、數值或布林值表示,通常與toString()
方法的返回值相同。
4. 操作符
ECMA-262
描述了一組用於操作資料值的操作符
,包括算術操作符
(如加號和減號)、位操作符
、關係操作符
和相等操作符
。
4.1 一元操作符
只能操作一個值的操作符叫做一元操作符 。
一元操作符有:++
、--
、+=
、-=
4.2 位操作符
位操作符用於在最基本的層次上,即按記憶體中表示數值的位來運算元值。
4.3 布林操作符
一共有三個值:與(&&)
、或(||)
、非(!)
!
: 非真即為假,非假即為真。
&&
和||
都有短路操作:即如果第一個運算元能夠決定結果,那麼就不會再對第二個運算元求值。
&& ||
4.4 算術運算子
算術運算子有:+
、-
、*
、/
、%
-
+
有以下用法:
1.數值相加:如果加號兩邊的運算元都是數值,進行正常的求和計算var sum = 3 + 2;//5
2.字元拼接:加號兩邊的運算元只要有一個是字串,則進行字元拼接var sum = "3" + 2;//32
-
-
用法:進行減法運算,如果有一個運算元不是數值,則先在後臺呼叫Number()
函式將其轉換為數值,再進行運算。如:var res = 5 - true;//4,true 被轉換成了 1 var res = NaN - 1;//NaN var res = 5 - 3;//2 var res = 5 - "";//5," "被轉換成了 0 var res = 5 - "3";//2,"3" 被轉換成了 3 var res = 5 - null;//5,null 被轉換成了 0
-
*
、/
、%
用法:均為正常的數學運算,與NaN
進行運算均為NaN
。
4.5 關係操作符
關係操作符有:>
、<
、>=
、<=
關係操作符有以下幾種規則:
- 如果兩個運算元都是數值,則進行數值比較;
- 如果兩個運算元都是字串,則比較字串對應的字元編碼值;
- 如果一個運算元是數值,則將另一個運算元轉為數值,再進行數值比較;
-
如果一個運算元是物件,則呼叫這個物件的
valueOf()
方法,用得到的結果按照前面的規則進行比較。如果沒有valueOf()
方法,則呼叫toString()
方法,並用得到的結果與前面的規則進行比較。
例如:var res = 3 > 5;//false var res = "23" < "3";//true var res = "23" < 3;//false var res = "a" < 3;//false,"a" 被轉換成了 NaN
注意: 任何運算元與NaN
進行關係比較,結果都是false
。
4.6 相等操作符
==
和!=
—— 先轉換再比較;===
和!==
—— 僅比較而不轉換。
1.在轉換不同的資料型別時,相等(==
) 和 不相等(!=
) 操作符遵循下列基本規則:
-
如果有一個運算元是布林值,則比較之前先將其進行數值轉換——
false
轉換為0
,true
轉換為1
; - 如果運算元一個是字串,另一個是數值,先將字元轉進行轉換,再進行對比;
-
如果一個運算元是物件,另一個不是,則呼叫物件的
valueOf()
方法,用得到的值按之前的規則進行對比; -
null
==undefined
; -
要比較等價性之前,不能將
null
和undefined
轉換成其他任何值; -
NaN
不等於任何值,包括其自身; -
如果兩個運算元都是物件,則要比較它們是不是同一個物件。如果兩個運算元都指向同一個物件,則相等操作符返回
true
,否則返回false
。
有以下例子:null == undefined;//true NaN == NaN;//false NaN != NaN;//true 5 == NaN;//false false == 0;//true true == 1;//true true == 2;//false null == 0;//false "3"== 3;//true
-
全等(
===
) 和 不全等(!==
):不經過型別轉換就進行比較。如下所示:
"33" == 33;//true,型別轉換後值相等 "33" === 33;//false,不同的資料型別不同
-
4.7 條件操作符
var max = (num1 > num2) ? num1 : num2
在這個例子中,max
中將會儲存一個最大的值。這個表示式的意思是,如果num1
大於num2
(關係表示式返回true
),則將num1
的值賦給max
;否則,將num2
的值賦值給max
。
4.8 賦值操作符
簡單的賦值操作符由=
表示,其作用就是把右側的值賦值給左側的變數。
例如:
var num = 10;
5. 語句
ECMA-262
規定了一組語句(也稱為流控制語句)。從本質上看,語句定義了ECMAScript
中的主要語法,語句通常使用一個或多個關鍵字來完成給定任務。
5.1 if 語句
語法:
if (condition) statement1 else statement2
例如:
if( i > 5 ){ aler( "it larger than 5" ) }else if( i < 0 ){ aler( "it smaller than 0" ) }else{ alert( "Between 0 and 5" ) }
5.2 do-while 語句
在對條件表示式求值之前,迴圈體內的程式碼至少會被執行一次。
語法:
do { statement } while ( expression );
例如:
var i = 0; do { i += 2; } while ( i < 10 ); alert (i);//10
5.3 while 語句
在迴圈體內的程式碼被執行之前,就會對出口條件求值。因此,迴圈體內的程式碼有可能永遠不會被執行。
語法:
while ( expression ) statement
例如:
var i = 0; while ( i < 10 ){ i += 2; } aler (i);//10
5.4 for 語句
語法:
for ( initialization; expression; post-loop-expression ) statement
例如:
var count = 10; for ( var i = 0; i < count; i++ ){ console.log(i);//0,1,2,3,4,5,6,7,8,9 } 相當於: var count = 10; var i = 0; while ( i< count ){ console.log(i); i++; }
注意:for
語句中的初始化表示式、控制表示式和迴圈後表示式都是可選的。將這三個表示式全部省略,就會建立一個無限迴圈,例如:
for ( ; ; ) {//無限迴圈 doSomething(); }
而只給出控制表示式實際上就把for
迴圈轉換成了while
迴圈,例如:
var count = 10; var i = 0; for ( ; i < count; ){ console.log(i); i++; }
5.5 for-in 語句
for-in
語句是一種精準的迭代語句,可以用來列舉物件的屬性。
語法:
for ( property in expression ) statement
例如:
var obj = { a:'aa', b:'bb', c:'cc' } for(var propName in obj){ console.log(propName);//"a","b","c" }
5.6 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
在這個例子中,迴圈體中的i
為5
的時候,則執行break
語句退出迴圈。num++
總共執行了4
次,所以num
的值為4
。如果這裡把break
替換為continue
,則可以看到另一種結果:
var num = 0; for( var i = 1; i < 10; i++ ){ if( i % 5 == 0 ){ continue; } num++; } alert(num);//8
例子的結果為8
,也就是num++
總共執行了8
次。當i
等於5
時,迴圈會在num
再次遞增之前退出,但接下來,會繼續執行下一次迴圈,即i
的值等於6
的迴圈,此時num
為5
,然後繼續執行迴圈,知道i
等於10
結束迴圈。而最終num
值之所以為8
,是因為continue
語句導致它少遞增了一次。
5.7 switch 語句
switch
語句與if
語句的關係最為密切,而且也是在其他語言中普遍使用的一種流控制語句。
語法:
switch (expression) { case value: statement break; case value: statement break; case value: statement break; default: statement }
switch
語句中的每一種情形(case
)的含義是:“如果表示式等於這個值(value
),則執行後面的語句(statement
)”。而break
關鍵字會導致程式碼執行流跳出switch
語句。如果省略break
關鍵字,就會導致執行完當前case
後,繼續執行下一個case
。最後的default
關鍵字則用於在表示式不匹配前面任何一種情形的時候,執行機動程式碼(因此,也相當於一個else
語句)。
例如:
if( i == 25 ){ alert("25"); }else if( i == 35 ){ alert("35"); }else if( i == 45 ){ alert("45"); }else{ alert("Other"); }
而與此等價的switch
語句如下所示:
switch( i ) { case 25; alert ("25"); break; case 35; alert ("35"); break; case 45; alert ("45"); break; default: alert ("Other");d }
6. 函式
通過函式可以封裝任意多條語句,而且可以在任何地方,任何時候呼叫執行。ECMAScript
中的函式使用function
關鍵字來宣告,後跟一組引數以及函式體。
語法:
function fn ( a,b,...,n ){ statements }
例如:
function sayHi( name , message ){ alert( "Hello" + name + "," + message ) }
呼叫sayHi()
函式的程式碼如下所示:
sayHi( " Lily" , "how are you today ?");
ECMAScript
中的函式在定義時不必指定是否返回值。實際上,任何函式在任何時候都可以通過return
語句後跟要返回的值來實現返回值。例如:
function sum ( num1 , num2 ){ return num1 + num2; }
呼叫這個函式的程式碼如下:
var result = sum ( 3 , 5 );
位於return
語句之後的任何程式碼都永遠不會執行。
function sum( num1 , num2 ){ return num1 + num2; alert("hello");//永遠不會執行 }