JavaScript基本語法

2018-07-24 11:49 更新

目錄

語句

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)于分號的更多介紹,請看后文《代碼風(fēng)格》一節(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;

如果只是聲明變量而沒有賦值,則該變量的值是undefinedundefined是一個JavaScript關(guān)鍵字,表示“無定義”。

var a;
a // undefined

如果變量賦值的時候,忘了寫var命令,這條語句也是有效的。

var a = 1;
// 基本等同
a = 1;

但是,不寫var的做法,不利于表達意圖,而且容易不知不覺地創(chuàng)建全局變量,所以建議總是使用var命令聲明變量。

嚴格地說,var a = 1a = 1,這兩條語句的效果不完全一樣,主要體現(xiàn)在delete命令無法刪除前者。不過,絕大多數(shù)情況下,這種差異是可以忽略的。

如果一個變量沒有聲明就直接使用,JavaScript會報錯,告訴你變量未定義。

x
// ReferenceError: x is not defined

上面代碼直接使用變量x,系統(tǒng)就報錯,告訴你變量x沒有聲明。

可以在同一條var命令中聲明多個變量。

var a, b;

JavaScript 是一種動態(tài)類型語言,也就是說,變量的類型沒有限制,可以賦予各種類型的值。

var a = 1;
a = 'hello';

上面代碼中,變量a起先被賦值為一個數(shù)值,后來又被重新賦值為一個字符串。第二次賦值的時候,因為變量a已經(jīng)存在,所以不需要使用var命令。

如果使用var重新聲明一個已經(jīng)存在的變量,是無效的。

var x = 1;
var x;
x // 1

上面代碼中,變量x聲明了兩次,第二次聲明是無效的。

但是,如果第二次聲明的同時還賦值了,則會覆蓋掉前面的值。

var x = 1;
var x = 2;

// 等同于

var x = 1;
var x;
x = 2;

變量提升

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)識符

標(biāo)識符(identifier)是用來識別具體對象的一個名稱。最常見的標(biāo)識符就是變量名,以及后面要提到的函數(shù)名。JavaScript語言的標(biāo)識符對大小寫敏感,所以aA是兩個不同的標(biāo)識符。

標(biāo)識符有一套命名規(guī)則,不符合規(guī)則的就是非法標(biāo)識符。JavaScript引擎遇到非法標(biāo)識符,就會報錯。

簡單說,標(biāo)識符命名規(guī)則如下:

  • 第一個字符,可以是任意Unicode字母(包括英文字母和其他語言的字母),以及美元符號($)和下劃線(_)。
  • 第二個字符及后面的字符,除了Unicode字母、美元符號和下劃線,還可以用數(shù)字0-9。

下面這些都是合法的標(biāo)識符。

arg0
_tmp
$elem
π

下面這些則是不合法的標(biāo)識符。

1a  // 第一個字符不能是數(shù)字
23  // 同上
***  // 標(biāo)識符不能包含星號
a+b  // 標(biāo)識符不能包含加號
-d  // 標(biāo)識符不能包含減號或連詞線

中文是合法的標(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提供兩種注釋:一種是單行注釋,用//起頭;另一種是多行注釋,放在/* 和 */之間。

// 這是單行注釋

/*
 這是
 多行
 注釋
*/

此外,由于歷史上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。

區(qū)塊

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),比如forif、while、function等。

條件語句

條件語句提供一種語法構(gòu)造,只有滿足某個條件,才會執(zhí)行相應(yīng)的語句。JavaScript提供if結(jié)構(gòu)和switch結(jié)構(gòu),完成條件判斷。

if 結(jié)構(gòu)

if結(jié)構(gòu)先判斷一個表達式的布爾值,然后根據(jù)布爾值的真?zhèn)?,?zhí)行不同的語句。

if (expression)
  statement;

// 或者

if (expression) statement;

上面是if結(jié)構(gòu)的基本形式。需要注意的是,expression(表達式)必須放在圓括號中,表示對表達式求值。如果結(jié)果為true,就執(zhí)行緊跟在后面的語句(statement);如果結(jié)果為false,則跳過statement的部分。

if (m === 3)
  m += 1;	

上面代碼表示,只有在m等于3時,才會將其值加上1。

這種寫法要求條件表達式后面只能有一個語句。如果想執(zhí)行多個語句,必須在if的條件判斷之后,加上大括號,表示代碼塊。

if (m === 3) {
  m += 1;
}

建議總是在if語句中使用大括號,因為這樣方便插入語句。

注意,if后面的表達式,不要混淆“賦值表達式”(=)與“嚴格相等運算符”(===)或“相等運算符”(==)。因為,“賦值表達式”不具有比較作用。

var x = 1;
var y = 2;
if (x = y) {
  console.log(x);
}
// "2"

上面代碼的原意是,當(dāng)x等于y的時候,才執(zhí)行相關(guān)語句。但是,不小心將“嚴格相等運算符”寫成“賦值表達式”,結(jié)果變成了將y賦值給x,然后條件就變成了,變量x的值(等于2)自動轉(zhuǎn)為布爾值以后,判斷其是否為true。

這種錯誤可以正常生成一個布爾值,因而不會報錯。為了避免這種情況,有些開發(fā)者習(xí)慣將常量寫在運算符的左邊,這樣的話,一旦不小心將相等運算符寫成賦值運算符,就會報錯,因為常量不能被賦值。

if (x = 2) { // 不報錯
if (2 = x) { // 報錯

至于為什么優(yōu)先采用“嚴格相等運算符”(===),而不是“相等運算符”(==),請參考《運算符》一節(jié)。

if…else結(jié)構(gòu)

if代碼塊后面,還可以跟一個else代碼塊,表示不滿足條件時,所要執(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

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)。

var x = 1;

switch (x) {
  case 1:
    console.log('x 于1');
  case 2:
    console.log('x 等于2');
  default:
    console.log('x 等于其他值');
}
// x等于1
// x等于2
// x等于其他值

上面代碼中,case代碼塊之中沒有break語句,導(dǎo)致不會跳出switch結(jié)構(gòu),而會一直執(zhí)行下去。

switch語句部分和case語句部分,都可以使用表達式。

switch(1 + 3) {
  case 2 + 2:
    f();
    break;
  default:
    neverhappens();
}

上面代碼的default部分,是永遠不會執(zhí)行到的。

需要注意的是,switch語句后面的表達式與case語句后面的表示式,在比較運行結(jié)果時,采用的是嚴格相等運算符(===),而不是相等運算符(==),這意味著比較時不會發(fā)生類型轉(zhuǎn)換。

var x = 1;

switch (x) {
  case true:
    console.log('x發(fā)生類型轉(zhuǎn)換');
  default:
    console.log('x沒有發(fā)生類型轉(zhuǎn)換');
}
// x沒有發(fā)生類型轉(zhuǎn)換

上面代碼中,由于變量x沒有發(fā)生類型轉(zhuǎn)換,所以不會執(zhí)行case true的情況。這表明,switch語句內(nèi)部采用的是“嚴格相等運算符”,詳細解釋請參考《運算符》一節(jié)。

三元運算符 ?:

JavaScript還有一個三元運算符(即該運算符需要三個運算子)?:,也可以用于邏輯判斷。

(condition) ? expr1 : expr2

上面代碼中,如果conditiontrue,則返回expr1的值,否則返回expr2的值。

var even = (n % 2 === 0) ? true : false;

上面代碼中,如果n可以被2整除,則even等于true,否則等于false。它等同于下面的形式。

var even;
if (n % 2 === 0) {
  even = true;
} else {
  even = false;
}

這個三元運算符可以被視為if...else...的簡寫形式,因此可以用于多種場合。

var myVar;
console.log( myVar
  ? 'myVar has a value'
  : 'myVar do not has a value'
)
// myVar do not has a value

上面代碼利用三元運算符,輸出相應(yīng)的提示。

var msg = 'The number '
  + n
  + ' is '
  + ((n % 2 === 0) ? 'even' : 'odd');

上面代碼利用三元運算符,在字符串之中插入不同的值。

循環(huán)語句

循環(huán)語句用于重復(fù)執(zhí)行某個操作,它有多種形式。

while循環(huán)

While語句包括一個循環(huán)條件和一段代碼塊,只要條件為真,就不斷循環(huán)執(zhí)行代碼塊。

while (expression)
  statement;

// 或者

while (expression) statement;

while語句的循環(huán)條件是一個表達式(express),必須放在圓括號中。代碼塊部分,如果只有一條語句(statement),可以省略大括號,否則就必須加上大括號。

while (expression) {
  statement;
}

下面是while語句的一個例子。

var i = 0;

while (i < 100) {
  console.log('i當(dāng)前為:' + i);
  i += 1;
}

上面的代碼將循環(huán)100次,直到i等于100為止。

下面的例子是一個無限循環(huán),因為條件總是為真。

while (true) {
  console.log('Hello, world');
}

for循環(huán)

for語句是循環(huán)命令的另一種形式,可以指定循環(huán)的起點、終點和終止條件。它的格式如下。

for (initialize; test; increment)
  statement

// 或者

for (initialize; test; increment) {
  statement
}

for語句后面的括號里面,有三個表達式。

  • 初始化表達式(initialize):確定循環(huán)的初始值,只在循環(huán)開始時執(zhí)行一次。
  • 測試表達式(test):檢查循環(huán)條件,只要為真就進行后續(xù)操作。
  • 遞增表達式(increment):完成后續(xù)操作,然后返回上一步,再一次檢查循環(huán)條件。

下面是一個例子。

var x = 3;
for (var i = 0; i < x; i++) {
  console.log(i);
}
// 0
// 1
// 2

上面代碼中,初始化表達式是var i = 0,即初始化一個變量i;測試表達式是i < x,即只要i小于x,就會執(zhí)行循環(huán);遞增表達式是i++,即每次循環(huán)結(jié)束后,i增大1。

所有for循環(huán),都可以改寫成while循環(huán)。上面的例子改為while循環(huán),代碼如下。

var x = 3;
var i = 0;

while (i < x) {
  console.log(i);
  i++;
}

for語句的三個部分(initialize,test,increment),可以省略任何一個,也可以全部省略。

for ( ; ; ){
  console.log('Hello World');
}

上面代碼省略了for語句表達式的三個部分,結(jié)果就導(dǎo)致了一個無限循環(huán)。

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語句后面的分號不能省略。

下面是一個例子。

var x = 3;
var i = 0;

do {
  console.log(i);
  i++;
} while(i < x);

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)。

for循環(huán)也可以使用break語句跳出循環(huán)。

for (var i = 0; i < 5; i++) {
  console.log(i);
  if (i === 3)
    break;
}
// 0
// 1
// 2
// 3

上面代碼執(zhí)行到i等于3,就會跳出循環(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)。

標(biāo)簽(label)

JavaScript語言允許,語句的前面有標(biāo)簽(label),相當(dāng)于定位符,用于跳轉(zhuǎn)到程序的任意位置,標(biāo)簽的格式如下。

label:
  statement

標(biāo)簽可以是任意的標(biāo)識符,但是不能是保留字,語句部分可以是任意語句。

標(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ū)塊,break命令后面加上了top標(biāo)簽(注意,top不用加引號),滿足條件時,直接跳出雙層循環(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)簽名,滿足條件時,會跳過當(dāng)前循環(huán),直接進入下一輪外層循環(huán)。如果continue語句后面不使用標(biāo)簽,則只能進入下一輪的內(nèi)層循環(huán)。

參考鏈接

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號