W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
JavaScript程序的執(zhí)行單位為行(line),也就是一行一行地執(zhí)行。一般情況下,每一行就是一個語句。
語句(statement)是為了完成某種任務(wù)而進行的操作,比如下面就是一行賦值語句:
var a = 1 + 3;
這條語句先用var命令,聲明了變量a,然后將1 + 3
的運算結(jié)果賦值給變量a。
1 + 3
叫做表達式(expression),指一個為了得到返回值的計算式。語句和表達式的區(qū)別在于,前者主要為了進行某種操作,一般情況下不需要返回值;后者則是為了得到返回值,一定會返回一個值。
凡是JavaScript語言中預(yù)期為值的地方,都可以使用表達式。比如,賦值語句的等號右邊,預(yù)期是一個值,因此可以放置各種表達式。一條語句可以包含多個表達式。
語句以分號結(jié)尾,一個分號就表示一個語句結(jié)束。多個語句可以寫在一行內(nèi)。
var a = 1 + 3 ; var b = "abc";
分號前面可以沒有任何內(nèi)容,JavaScript引擎將其視為空語句。
;;;
上面的代碼就表示3個空語句。(關(guān)于分號的更多介紹,請看后文《結(jié)尾的分號》一節(jié)。)
表達式不需要分號結(jié)尾。一旦在表達式后面添加分號,則JavaScript引擎就將表達式視為語句,這樣會產(chǎn)生一些沒有任何意義的語句。
1 + 3;
"abc";
上面兩行語句有返回值,但是沒有任何意義,因為只是返回一個單純的值,沒有任何其他操作。
變量是對“值”的引用,使用變量等同于引用一個值。每一個變量都有一個變量名。
var a = 1;
上面的代碼先聲明變量a,然后在變量a與數(shù)值1之間建立引用關(guān)系,也稱將數(shù)值1“賦值”給變量a。以后,引用變量a就會得到數(shù)值1。最前面的var,是變量聲明命令。它表示通知解釋引擎,要創(chuàng)建一個變量a。
變量的聲明和賦值,是分開的兩個步驟,上面的代碼將它們合在了一起,實際的步驟是下面這樣。
var a;
a = 1;
如果只是聲明變量而沒有賦值,則該變量的值為undefined。
var a;
a
// undefined
JavaScript允許省略var,直接對未聲明的變量賦值。也就是說,var a = 1 與 a = 1,這兩條語句的效果相同。但是由于這樣的做法很容易不知不覺地創(chuàng)建全局變量(尤其是在函數(shù)內(nèi)部),所以建議總是使用var命令聲明變量。
嚴(yán)格地說,var a = 1 與 a = 1,這兩條語句的效果不完全一樣,主要體現(xiàn)在delete命令無法刪除前者。不過,絕大多數(shù)情況下,這種差異是可以忽略的。
如果一個變量沒有聲明就直接使用,JavaScript會報錯,告訴你變量未定義。
x
// ReferenceError: x is not defined
上面代碼直接使用變量x,系統(tǒng)就報錯,告訴你變量x沒有聲明。
可以在同一條var命令中聲明多個變量。
var a,b;
JavaScirpt是一種動態(tài)類型語言,也就是說,變量的類型沒有限制,可以賦予各種類型的值。
var a = 1;
a = "hello";
上面代碼中,變量a起先被賦值為一個數(shù)值,后來又被重新賦值為一個字符串。第二次賦值的時候,因為變量a已經(jīng)存在,所以不需要使用var命令。如果用了,就等于重新聲明一個變量a,會覆蓋掉前面的同名變量。
JavaScript引擎的工作方式是,先解析代碼,獲取所有被聲明的變量,然后再一行一行地運行。這造成的結(jié)果,就是所有的變量的聲明語句,都會被提升到代碼的頭部,這就叫做變量提升(hoisting)。
console.log(a);
var a = 1;
上面代碼首先使用console.log方法,在控制臺(console)顯示變量a的值。這時變量a還沒有聲明和賦值,所以這是一種錯誤的做法,但是實際上不會報錯。因為存在變量提升,真正運行的是下面的代碼:
var a;
console.log(a);
a = 1;
最后的結(jié)果是顯示undefined,表示變量a已聲明,但還未賦值。
請注意,變量提升只對var命令聲明的變量有效,如果一個變量不是用var命令聲明的,就不會發(fā)生變量提升。
console.log(b);
b = 1;
上面的語句將會報錯,提示“ReferenceError: b is not defined”,即變量b未聲明,這是因為b不是用var命令聲明的,JavaScript引擎不會將其提升,而只是視為對頂層對象的b屬性的賦值。
標(biāo)識符(identifier)是用來識別具體對象的一個名稱。最常見的標(biāo)識符就是變量名,以及后面要提到的函數(shù)名。JavaScript語言的標(biāo)識符對大小寫敏感,所以a和A是兩個不同的標(biāo)識符。
標(biāo)識符有一套命名規(guī)則,不符合規(guī)則的就是非法標(biāo)識符。JavaScript引擎遇到非法標(biāo)識符,就會報錯。
簡單說,標(biāo)識符命名規(guī)則如下:
下面這些都是合法的標(biāo)識符。
arg0
_tmp
$elem
π
下面這些則是不合法的標(biāo)識符。
1a
23
***
a+b
-d
中文是合法的標(biāo)識符,可以用作變量名。
var 臨時變量 = 1;
JavaScript有一些保留字,不能用作標(biāo)識符:arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield。
另外,還有三個詞雖然不是保留字,但是因為具有特別含義,也不應(yīng)該用作標(biāo)識符:Infinity、NaN、undefined。
源碼中被JavaScript引擎忽略的部分就叫做注釋,它的作用是對代碼進行解釋。Javascript提供兩種注釋:一種是單行注釋,用//起頭;另一種是多行注釋,放在/ 和 /之間。
// 這是單行注釋
/*
這是
多行
注釋
*/
本教程后面的代碼部分,會采用這兩種形式說明代碼的運行結(jié)果,以及需要注意的地方。
此外,由于歷史上JavaScript兼容HTML代碼的注釋,所以也被視為單行注釋。
x = 1; <!-- x = 2;
--> x = 3;
上面代碼中,只有x = 1
會執(zhí)行,其他的部分都被注釋掉了。
需要注意的是,-->只有在行首,才會被當(dāng)成單行注釋,否則就是一個運算符。
function countdown(n) {
while (n --> 0) console.log(n);
}
countdown(3)
// 2
// 1
// 0
上面代碼中,n --> 0
實際上會當(dāng)作n-- > 0
,因為輸出2、1、0。
JavaScript使用大括號,將多個相關(guān)的語句組合在一起,稱為“區(qū)塊”(block)。
與大多數(shù)編程語言不一樣,JavaScript的區(qū)塊不構(gòu)成單獨的作用域(scope)。也就是說,區(qū)塊中的變量與區(qū)塊外的變量,屬于同一個作用域。
{
var a = 1;
}
a // 1
上面代碼在區(qū)塊內(nèi)部,聲明并賦值了變量a,然后在區(qū)塊外部,變量a依然有效,這說明區(qū)塊不構(gòu)成單獨的作用域,與不使用區(qū)塊的情況沒有任何區(qū)別。所以,單獨使用的區(qū)塊在JavaScript中意義不大,很少出現(xiàn)。區(qū)塊往往用來構(gòu)成其他更復(fù)雜的語法結(jié)構(gòu),比如for、if、while、functions等。
JavaScript提供if結(jié)構(gòu)和switch結(jié)構(gòu),完成條件判斷。
(1)if 結(jié)構(gòu)
if結(jié)構(gòu)先判斷一個表達式的布爾值,然后根據(jù)布爾值的真?zhèn)危瑘?zhí)行不同的語句。
if (expression)
statement
上面是if結(jié)構(gòu)的基本形式。需要注意的是,expression(表達式)必須放在圓括號中,表示對表達式求值。如果結(jié)果為true,就執(zhí)行緊跟在后面的statement(語句);如果結(jié)果為false,則跳過statement。
if (m === 3)
m += 1;
上面代碼表示,只有在m等于3時,才會將其值加上1。
這種寫法要求statement只能有一個語句。如果想將多個語句放在statement之中,必須在if的條件判斷之后,加上大括號。
if (m === 3) {
m += 1;
}
建議總是在if語句中使用大括號,因為這樣方便插入語句。
(2)if...else結(jié)構(gòu)
if代碼塊后面,還可以跟一個else代碼塊,表示括號中的表示式為false時,所要執(zhí)行的代碼。
if (m === 3) {
// then
} else {
// else
}
上面代碼判斷變量m是否等于3,如果等于就執(zhí)行if代碼塊,否則執(zhí)行else代碼塊。
對同一個變量進行多次判斷時,多個if...else語句可以連寫在一起。
if (m === 0) {
// ...
} else if (m === 1) {
// ...
} else if (m === 2) {
// ...
} else {
// ...
}
else代碼塊總是跟隨離自己最近的那個if語句。
var m = 1;
var n = 2;
if (m !== 1)
if (n === 2) console.log('hello');
else console.log('world');
上面代碼不會有任何輸出,else代碼塊也不會得到執(zhí)行,因為它跟著的是最近的那個if語句,相當(dāng)于下面這樣。
if (m !== 1) {
if (n === 2) {
console.log('hello');
} else {
console.log('world');
}
}
如果想讓else代碼塊跟隨最上面的那個if語句,就要改變大括號的位置。
if (m !== 1) {
if (n === 2) {
console.log('hello');
}
} else {
console.log('world');
}
// world
(3)switch結(jié)構(gòu)
多個if...else連在一起使用的時候,可以轉(zhuǎn)為使用更方便的switch結(jié)構(gòu)。
switch (fruit) {
case "banana":
// ...
break;
case "apple":
// ...
break;
default:
// ...
}
上面代碼根據(jù)變量fruit的值,選擇執(zhí)行相應(yīng)的case。如果所有case都不符合,則執(zhí)行最后的default部分。需要注意的是,每個case代碼塊內(nèi)部的break語句不能少,否則會接下去執(zhí)行下一個case代碼塊,而不是跳出switch結(jié)構(gòu)。
switch語句部分和case語句部分,都可以使用表達式。
switch(1 + 3) {
case 2 + 2:
f();
break;
default:
neverhappens();
}
上面代碼的default部分,是永遠不會執(zhí)行到的。
需要注意的是,switch語句后面的表達式與case語句后面的表示式,在比較運行結(jié)果時,采用的是嚴(yán)格相等運算符(===),而不是相等運算符(==),這意味著比較時不會發(fā)生類型轉(zhuǎn)換。
switch結(jié)構(gòu)不利于代碼重用,往往可以用對象形式重寫。
var o = {
banana: function (){ return },
apple: function (){ return },
default: function (){ return }
};
if (o[fruit]){
o[fruit]();
} else {
o['default']();
}
循環(huán)語句用于重復(fù)執(zhí)行某個操作,它有多種形式。
(1)while循環(huán)
While語句包括一個循環(huán)條件,只要該條件為真,就不斷循環(huán)。
while (expression)
statement
while語句的循環(huán)條件是一個表達式(express),必須放在圓括號中。語句(statement)部分默認(rèn)只能寫一條語句,如果需要包括多條語句,必須添加大括號。
while (expression){
statement
}
下面是while語句的一個例子。
var i = 0;
while (i<100){
console.log('i當(dāng)前為:' + i);
i++;
}
上面的代碼將循環(huán)100次,直到i等于100為止。
(2)for循環(huán)
for語句是循環(huán)命令的另一種形式。
for(initialize; test; increment)
statement
// 或者
for(initialize; test; increment){
statement
}
它分成三步:
下面是一個循環(huán)打印數(shù)組每個元素的例子。
for (var i=0; i < arr.length; i++) {
console.log(arr[i]);
}
所有for循環(huán),都可以改寫成while循環(huán)。
var i = 0;
while (i < arr.length) {
console.log(arr[i]);
i++;
}
for語句表達式的三個部分(initialize,test,increment),可以省略任何一個,也可以全部省略。
for (;;){
console.log('Hello World');
}
上面代碼省略了for語句表達式的三個部分,結(jié)果就導(dǎo)致了一個無限循環(huán)。
(3)do...while循環(huán)
do...while循環(huán)與while循環(huán)類似,唯一的區(qū)別就是先運行一次循環(huán)體,然后判斷循環(huán)條件。
do
statement
while(expression);
// 或者
do {
statement
} while(expression);
不管條件是否為真,do..while循環(huán)至少運行一次,這是這種結(jié)構(gòu)最大的特點。另外,while語句后面的分號不能省略。
(4)break語句和continue語句
break語句和continue語句都具有跳轉(zhuǎn)作用,可以讓代碼不按既有的順序執(zhí)行。
break語句用于跳出代碼塊或循環(huán)。
var i = 0;
while (i<100){
console.log('i當(dāng)前為:' + i);
i++;
if (i === 10) break;
}
上面代碼只會執(zhí)行10次循環(huán),一旦i等于10,就會跳出循環(huán)。
continue語句用于立即終止本次循環(huán),返回循環(huán)結(jié)構(gòu)的頭部,開始下一次循環(huán)。
var i = 0;
while (i<100){
i++;
if (i%2===0) continue;
console.log('i當(dāng)前為:' + i);
}
上面代碼只有在i為奇數(shù)時,才會輸出i的值。如果i為偶數(shù),則直接進入下一輪循環(huán)。
如果存在多重循環(huán),不帶參數(shù)的break語句和continue語句都只針對最內(nèi)層循環(huán)。
(5)標(biāo)簽(label)
JavaScript語言允許,語句的前面有標(biāo)簽(label)。標(biāo)簽通常與break語句和continue語句配合使用,跳出特定的循環(huán)。
top:
for (var i=0;i<3;i++){
for (var j=0;j<3;j++){
if (i===1 && j===1) break top;
console.log("i="+i+",j="+j);
}
}
// i=0,j=0
// i=0,j=1
// i=0,j=2
// i=1,j=0
上面代碼為一個雙重循環(huán)區(qū)塊,加上了top標(biāo)簽(注意,top不用加引號)。當(dāng)滿足一定條件時,使用break語句加上標(biāo)簽名,直接跳出雙層循環(huán)。如果break語句后面不使用標(biāo)簽,則只能跳出內(nèi)層循環(huán),進入下一次的外層循環(huán)。
continue語句也可以與標(biāo)簽配合使用。
top:
for (var i=0;i<3;i++){
for (var j=0;j<3;j++){
if (i===1 && j===1) continue top;
console.log("i="+i+",j="+j);
}
}
// i=0,j=0
// i=0,j=1
// i=0,j=2
// i=1,j=0
// i=2,j=0
// i=2,j=1
// i=2,j=2
上面代碼在滿足一定條件時,使用continue語句加上標(biāo)簽名,直接進入下一輪外層循環(huán)。如果continue語句后面不使用標(biāo)簽,則只能進入下一輪的內(nèi)層循環(huán)。
JavaScript語言的每一個值,都屬于某一種數(shù)據(jù)類型。JavaScript的數(shù)據(jù)類型,共有六個類別和兩個特殊值。
六個類別的數(shù)據(jù)類型又可以分成兩組:原始類型(primitive type)和合成類型(complex type)。
原始類型包括三種數(shù)據(jù)類型。
“數(shù)值”就是整數(shù)和小數(shù)(比如1和3.14),“字符串”就是由多個字符組成的文本(比如"Hello World"),“布爾值”則是true(真)和false(假)兩個特定值。
合成類型也包括三種數(shù)據(jù)類型。
對象和數(shù)組是兩種不同的數(shù)據(jù)組合方式,而函數(shù)其實是處理數(shù)據(jù)的方法。JavaScript把函數(shù)當(dāng)成一種數(shù)據(jù)類型,可以像其他類型的數(shù)據(jù)一樣,進行賦值和傳遞,這為編程帶來了很大的靈活性,體現(xiàn)了JavaScript作為“函數(shù)式語言”的本質(zhì)。
這里需要明確的是,JavaScript的所有數(shù)據(jù),都可以視為對象。不僅合成類型的數(shù)組和函數(shù)屬于對象的特例,就連原始類型的數(shù)據(jù)(數(shù)值、字符串、布爾值)也可以用對象方式調(diào)用。
除了上面這六個類別,JavaScript還定義了兩個特殊值null和undefined。
本書將分別詳細介紹這六個類別和兩個特殊值。其中,兩個特殊值和布爾類型比較簡單,將在本節(jié)介紹,其他類型將各自有單獨的一節(jié)。
JavaScript有三種方法,可以確定一個值到底是什么類型。
instanceof運算符和Object.prototype.toString方法,將在后文相關(guān)章節(jié)介紹。這里著重介紹typeof 運算符。
typeof運算符可以返回一個值的數(shù)據(jù)類型,可能有以下結(jié)果。
(1)原始類型
數(shù)值、字符串、布爾值分別返回number、string、boolean。
typeof 123 // "number"
typeof "123" // "string"
typeof false // "boolean"
(2)函數(shù)
函數(shù)返回function。
// 定義一個空函數(shù)
function f(){}
typeof f
// "function"
(3)undefined
undefined返回undefined。
typeof undefined
// "undefined"
利用這一點,typeof可以用來檢查一個沒有聲明的變量,而不報錯。
v
// ReferenceError: v is not defined
typeof v
// "undefined"
實際編程中,這個特點通常用在判斷語句。
// 錯誤的寫法
if (v){
// ...
}
// ReferenceError: v is not defined
// 正確的寫法
if (typeof v === "undefined"){
// ...
}
(4)其他
除此以外,都返回object。
typeof window // "object"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
從上面代碼可以看到,空數(shù)組([])的類型也是object,這表示在JavaScript內(nèi)部,數(shù)組本質(zhì)上只是一種特殊的對象。另外,null的類型也是object,這是由于歷史原因造成的,為了兼容以前的代碼,后來就沒法修改了,并不是說null就屬于對象,本質(zhì)上null是一個類似于undefined的特殊值。
既然typeof對數(shù)組(array)和對象(object)的顯示結(jié)果都是object,那么怎么區(qū)分它們呢?instanceof運算符可以做到。
var o = {};
var a = [];
o instanceof Array // false
a instanceof Array // true
instanceof運算符的詳細解釋,請見《面向?qū)ο缶幊獭芬徽隆?/p>
(1)相似性
首先,null與undefined都可以表示“無”,含義非常相似。將一個變量賦值為undefined或null,老實說,幾乎沒區(qū)別。
var a = undefined;
// 或者
var a = null;
上面代碼中,a變量分別被賦值為undefined和null,這兩種寫法幾乎等價。
在if語句中,都會被自動轉(zhuǎn)為false,相等運算符甚至直接報告兩者相等。
if (!undefined)
console.log('undefined is false');
// undefined is false
if (!null)
console.log('null is false');
// null is false
undefined == null
// true
上面代碼說明,兩者的行為是何等相似!Google公司開發(fā)的JavaScript語言的替代品Dart語言,就明確規(guī)定只有null,沒有undefined!
既然含義與用法都差不多,為什么要同時設(shè)置兩個這樣的值,這不是無端增加復(fù)雜度,令初學(xué)者困擾嗎?這與歷史原因有關(guān)。
(2)歷史原因
1995年JavaScript誕生時,最初像Java一樣,只設(shè)置了null作為表示"無"的值。根據(jù)C語言的傳統(tǒng),null被設(shè)計成可以自動轉(zhuǎn)為0。
Number(null)
// 0
5 + null
// 5
但是,JavaScript的設(shè)計者Brendan Eich,覺得這樣做還不夠,有兩個原因。
首先,null像在Java里一樣,被當(dāng)成一個對象。但是,JavaScript的數(shù)據(jù)類型分成原始類型和合成類型兩大類,Brendan Eich覺得表示"無"的值最好不是對象。
其次,JavaScript的最初版本沒有包括錯誤處理機制,發(fā)生數(shù)據(jù)類型不匹配時,往往是自動轉(zhuǎn)換類型或者默默地失敗。Brendan Eich覺得,如果null自動轉(zhuǎn)為0,很不容易發(fā)現(xiàn)錯誤。
因此,Brendan Eich又設(shè)計了一個undefined。他是這樣區(qū)分的:null是一個表示"無"的對象,轉(zhuǎn)為數(shù)值時為0;undefined是一個表示"無"的原始值,轉(zhuǎn)為數(shù)值時為NaN。
Number(undefined)
// NaN
5 + undefined
// NaN
但是,這樣的區(qū)分在實踐中很快就被證明不可行。目前,null和undefined基本是同義的,只有一些細微的差別。
(3)用法和含義
對于null和undefined,可以大致上像下面這樣理解。
null表示"沒有對象",即該處不應(yīng)該有值。典型用法是:
作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象。
undefined表示"缺少值",就是此處應(yīng)該有一個值,但是還未定義。典型用法是:
變量被聲明了,但沒有賦值時,就等于undefined。
調(diào)用函數(shù)時,應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于undefined。
對象沒有賦值的屬性,該屬性的值為undefined。
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
(4)null的特殊之處
null的特殊之處在于,JavaScript把它包含在對象類型(object)之中。
typeof null // "object"
上面代碼表示,查詢null的類型,JavaScript返回object(對象)。
這并不是說null的數(shù)據(jù)類型就是對象,而是JavaScript早期部署中的一個約定俗成,其實不完全正確,后來再想改已經(jīng)太晚了,會破壞現(xiàn)存代碼,所以一直保留至今。
(5)注意點
JavaScript的標(biāo)識名區(qū)分大小寫,所以undefined和null不同于Undefined和Null(或者其他僅僅大小寫不同的詞形),后者只是普通的變量名。
布爾值代表“真”和“假”兩個狀態(tài)。“真”用關(guān)鍵字true表示,“假”用關(guān)鍵字false表示。布爾值只有這兩個值。
下列運算符會返回布爾值:
如果JavaScript預(yù)期某個位置應(yīng)該是布爾值,會將該位置上現(xiàn)有的值自動轉(zhuǎn)為布爾值。轉(zhuǎn)換規(guī)則是除了下面六個值被轉(zhuǎn)為false,其他值都視為true。
布爾值往往用于程序流程的控制,請看一個例子。
if (""){ console.log(true);}
// 沒有任何輸出
上面代碼的if命令后面的判斷條件,預(yù)期應(yīng)該是一個布爾值,所以JavaScript自動將空字符串,轉(zhuǎn)為布爾值false,導(dǎo)致程序不會進入代碼塊,所以沒有任何輸出。
需要特別注意的是,空數(shù)組([])和空對象({})對應(yīng)的布爾值,都是true。
if ([]){ console.log(true);}
// true
if ({}){ console.log(true);}
// true
更多關(guān)于數(shù)據(jù)類型轉(zhuǎn)換的介紹,參見《數(shù)據(jù)類型轉(zhuǎn)換》一節(jié)。
分號表示一條語句的結(jié)尾。但是,有一些語法結(jié)構(gòu)不需要在語句的結(jié)尾添加分號,主要是以下三種情況。
(1)for和while循環(huán)
for(;;){} // 沒有分號
while(true){} // 沒有分號
需要注意的是do...while循環(huán)是有分號的。
do {
a--;
} while(a > 0); // 分號不能省略
(2)分支語句:if, switch, try
if (true) {} // 沒有分號
switch () {} // 沒有分號
try {} catch {} // 沒有分號
(3)函數(shù)的聲明語句
function f() {} // 沒有分號
但是函數(shù)表達式仍然要使用分號。
var f = function f() {};
以上三種情況,如果使用了分號,并不會出錯。因為,解釋引擎會把這個分號解釋為空語句。
除了本來就不寫分號的情況,JavaScript引擎還有一個特點,就是在應(yīng)該寫分號卻沒寫的情況下,它會自動添加(Automatic Semicolon Insertion,簡稱ASI)。
var a = b + c
// 等同于
var a = b + c;
但是,這種自動添加不是絕對的。如果下一行的開始可以與本行的結(jié)尾連在一起解釋,就不會自動添加分號。
var
a
=
3
// 等同于
var a = 3;
"abc"
.length
// 等同于
"abc".length
上面代碼舉了兩個例子,每行的尾部都沒有分號,JavaScript并不會自動添加分號,因為每行的結(jié)尾與下一行的開頭可以放在一起解釋。下面這個例子也不會自動添加分號。
3 * (2 * (4 + (3 - 5)))
+
(10 * (27 / 6))
// 等同于
3 * (2 * (4 + (3 - 5))) + (10 * (27 / 6))
這些例子還是比較容易看出來的,但是下面的例子就不那么容易發(fā)現(xiàn)了。它們都不會自動添加分號。
var a = b + c
(d+e).toString();
/* 結(jié)果報錯,因為兩行連在一起,
解釋為c(d+e),
即對函數(shù) c 的調(diào)用 */
a = b
/hi/g.exec(c).map(d);
/* 解釋為 a = b / hi / g.exec(c).map(d),
即把正則表達式的斜杠當(dāng)作除法運算符 */
var a = "b"
[ "red", "green" ].forEach(function(c) { console.log(c) })
/* 結(jié)果報錯,因為兩行連在一起,
解釋為"b"["red", "green"],
即把字符串當(dāng)作一個數(shù)組,按索引取值 */
var a = 0;
var f = function(x) { return x }
(a++)
/* f等于0,因為(a++)被
* 視為匿名函數(shù)的調(diào)用 */
return a +
b;
return (a
+ b)
obj.foo(arg1,
arg2)
一般來說,在沒有分號結(jié)尾的情況下,如果下一行起首的是(、 [ 、+、-、/這五個字符中的一個,分號不會被自動添加。只有下一行的開始與本行的結(jié)尾,無法放在一起解釋,JavaScript引擎才會自動添加分號。
if (a < 0) a = 0
console.log(a)
// 等同于下面的代碼,
// 因為0console沒有意義
if (a < 0) a = 0;
console.log(a)
另外,如果一行的起首是“自增”(++)或“自減”(--)運算符,則它們的前面會自動添加分號。
a = b = c = 1
a
++
b
--
c
console.log(a, b, c)
// 1 2 0
之所以會得到“1 2 0”的結(jié)果,原因是自增和自減運算符前,自動被加上了分號。上面的代碼實際上等同于下面的形式:
a = b = c = 1;
a;
++b;
--c;
如果continue、break、return和throw這四個語句后面,直接跟換行符,則會自動添加分號。這意味著,如果return語句返回的是一個對象的字面量,起首的大括號一定要寫在同一行,否則得不到預(yù)期結(jié)果。
return
{ first: "Jane" };
// 解釋成
return;
{ first: "Jane" };
由于解釋引擎自動添加分號的行為難以預(yù)測,因此編寫代碼的時候不應(yīng)該省略行尾的分號。
省略結(jié)尾的分號,還有一個問題。有些JavaScript代碼壓縮器不會自動添加分號,因此遇到?jīng)]有分號的結(jié)尾,就會讓代碼保持原狀,而不是壓縮成一行。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: