表達(dá)式和運算符
語句
表達(dá)式和運算符
- 屬性訪問表達(dá)式兩種寫法
(1)expression . identifer
(2)expression [ expression ] (適用于對象和數(shù)組)
注意:無論使用哪種方式,在“.”和“[”之前的表達(dá)式總是會先計算。如果計算結(jié)果是null或者undefined,表達(dá)式會拋出一個類型錯誤異常,因為兩個值都不能包含任意屬性。第一種寫法適用于要訪問的屬性名是合法的標(biāo)識符,并且需要知道要訪問的屬性的名字。如果屬性名稱是一個保留字或者包含空格和標(biāo)點符號,或是一個數(shù)組(對于數(shù)組來說),則必須使用方括號的寫法,同時如果屬性名是通過運算的出來的而不是固定值的時候也要用第二種寫法 - 關(guān)鍵字運算符 delete(刪除屬性)、typeof(檢測操作數(shù)類型)、void(返回undefined值)、instanceof(測試對象類)、in(測試屬性是否存在)
- 在JS中所有的數(shù)字都是浮點數(shù),除法運算的結(jié)果也是浮點型,比如5/2的結(jié)果是2.5而不是2.除數(shù)為0的運算結(jié)果為正無窮大或者負(fù)無窮大,而0/0的結(jié)果是NaN
- 取模運算“%”結(jié)果的符號和第一個操作數(shù)(被除數(shù))的符號保持一致,如5%2=1,-5%2的結(jié)果是-1,5%-2=1,取模運算的操作數(shù)也適用于浮點數(shù),如6.5%2.1=0.2
- “+”運算符。加好的轉(zhuǎn)換規(guī)則優(yōu)先考慮字符串的連接,如果其中一個操作數(shù)是字符串或者轉(zhuǎn)換成字符串的對象,另外一個操作數(shù)將會轉(zhuǎn)換為字符串,加法將進(jìn)行字符串的連接操作。如果兩個操作數(shù)都不是類字符串(string-like)的,那么都將進(jìn)行算數(shù)加法運算
一些例子如下:
1 + 2 // =>3: 加法
"1" + "2" // =>"12": 字符串連接
"1" + 2 // =>"12": 數(shù)字轉(zhuǎn)換成字符串后進(jìn)行字符串拼接
1 + {} // =>"1[object Object]": 對象轉(zhuǎn)換成字符串后進(jìn)行字符串拼接
true + true // =>2: 布爾值轉(zhuǎn)換成數(shù)字后做加法
1 + null // =>1: null轉(zhuǎn)換為0后做加法
1 + undefined // =>NaN: undefined轉(zhuǎn)換成NaN后做加法
需要注意的是,要考慮加法的結(jié)合律
1 + 2 + "blind mice" // => "3 blind mice"
1 + (2 + "bind mice") // => "12bind mice"
- 關(guān)系表達(dá)式。關(guān)系運算符用于測試兩個值之間的關(guān)系(比如相等、小于或“是...的屬性”),根據(jù)關(guān)系是否存在而返回true和false
- 相等運算符“==”和恒等運算符“===” 不相等“!=”和不嚴(yán)格相等“!==”
- JS對象的比較是引用的比較而不是值的比較。對象和其本身是相等的,但和其他任何對象都不相等。如果兩個不同的對象具有相同數(shù)量的屬性,相同的屬性名和值,他們依然是不相等的。相應(yīng)位置的數(shù)組元素是相等的兩個數(shù)組也是不相等的
- 嚴(yán)格運算符“===”首先計算其操作數(shù)的值,然后比較這兩個值,比較過程沒有任何類型轉(zhuǎn)換:
(1)若兩個值類型不相同,則不相等
(2)若兩個值都是null或者都是undefined,則不相等
(3)若兩個值都是布爾值true或者布爾值false,則相等
(4)若其中一個值是NaN或者兩個值都是NaN,則不相等。NaN和其他任何值都不相等,包括它本身,通過x!==x來判斷x是否是NaN,只有在x為NaN的時候,這個表達(dá)式才是true
(5)若兩個值都是數(shù)字且值相等,則它們相等。若一個值是0,一個值是-0,則它們同樣相等
(6)若兩個值是字符串,且所含的對應(yīng)位上的16位數(shù)完全相等,則它們相等。若兩個字符串可能含義完全一樣且所顯示出來的字符也一樣,但具有不同編碼的16位值,由于JS并不對Unicode進(jìn)行標(biāo)準(zhǔn)化的轉(zhuǎn)換,因此它們不相等。
(7)若兩個引用值指向同一個對象、數(shù)組或函數(shù),則相等。如果指向不同的對象,則它們是不等的,盡管兩個對象具有完全一樣的屬性。 - 相等運算符“==”并不是很嚴(yán)格。如果兩個操作數(shù)不是同一類型,那么相等運算符會嘗試進(jìn)行一些類型轉(zhuǎn)化,然后進(jìn)行比較:
若兩個操作數(shù)類型不同,“==”相等運算符也可能會認(rèn)為它們相等。檢測箱等會遵守如下規(guī)則和類型轉(zhuǎn)化:
1> 若一個值是null,另一個值是undefined,則它們相等;
2> 若一個值是數(shù)字,另一個是字符串,先將字符串轉(zhuǎn)換成數(shù)字,然后使用轉(zhuǎn)換后的值進(jìn)行比較;
3> 若一個值是true,則將其轉(zhuǎn)換成1后再進(jìn)行比較。若其中一個是false,則將其轉(zhuǎn)換成0后再進(jìn)行比較;
4> 若一個值是對象,另一個值是數(shù)字或者字符串,則是用轉(zhuǎn)換規(guī)則將對象轉(zhuǎn)換為原始值,然后再進(jìn)行比較。對象通過toString()方法或者valueOf()方法轉(zhuǎn)換為原始值。JS語言核心的內(nèi)置類首先嘗試使用valueOf(),在嘗試使用toString(),除了日期類,日期類只使用toString()轉(zhuǎn)換,那些不是JS語言核心中的對象通過各自的實現(xiàn)中定義的方法轉(zhuǎn)換成原始值。 - 這里舉一個判斷相等的小例子:"1" == true 這個表達(dá)式的結(jié)果是true,布爾值先轉(zhuǎn)成數(shù)字1,字符串"1"也轉(zhuǎn)換成了數(shù)字1,因為兩個數(shù)字相等,所以結(jié)果是true.
- in運算符。in運算符希望它的左操作數(shù)是一個字符串或者可以轉(zhuǎn)換為字符串,希望它的右操作數(shù)是一個對象。如果右側(cè)的對象擁有一個名為左操作數(shù)的屬性名,那么表達(dá)式返回true。
舉例說明:
var point = {x: 1, y:1}; // 定義一個對象
"x" in point // =>true:對象中有一個名為"x"的屬性
"z" in point // =>false對象中沒有一個名為"z"的屬性
"toString" in point // =>true:對象繼承了toString()方法
var data = [7, 8, 9]; // 擁有三個元素的數(shù)組
"0" in data // =>true:數(shù)組包含元素"0"
1 in data // =>true:數(shù)字轉(zhuǎn)換成字符串
3 in data // =>false:沒有索引為3的元素
- instanceof運算符,該運算符希望左操作數(shù)是一個對象,右操作數(shù)標(biāo)識對象的類。如果左側(cè)的對象是右側(cè)類的實例,則表達(dá)式返回true,否則返回false
var d = new Date(); // 通過Date()構(gòu)造函數(shù)來創(chuàng)建一個新對象
d instanceof Date; // true d是由Date()創(chuàng)建的
d instanceof Object; // true 所有的對象都是Object的實例
d instanceof Number; // false, d不是一個Number對象
var a = [1, 2, 3]; // 通過數(shù)組直接量的寫法創(chuàng)建一個數(shù)組
a instanceof Array; // true a是一個數(shù)組
a instanceof Object; // true 所有的數(shù)組都是對象
a instanceof RegExp; // false 數(shù)組不是正則表達(dá)式
需要注意的是,所有的對象都是Object實例
- 邏輯表達(dá)式--邏輯與&&,“&&”的行為有時候稱作“短路”,利用這個特性下邊兩個代碼語句完全相同:
if (a==b) stop() // 只有在a==b的時候才調(diào)用stop()
(a == b) && stop() // 同上 - 邏輯或|| 該云素服最常用的方式是用來從一組備選表達(dá)式中選出第一個真值表達(dá)式:
// 如果max_width已經(jīng)定義了,直接使用它;否則在preferences對象中查找max_width
// 如果沒有定義它,則是用一個寫死的常量
var max = max_width || preferences.max_width || 500;
這種慣用法通常在函數(shù)體內(nèi),用來給參數(shù)提供默認(rèn)值
// 將o的成員屬性復(fù)制到p中,并返回p
function copy(o, p) {
p = p || {}; // 如果向參數(shù)p沒有傳入任何對象,則使用一個新創(chuàng)建的對象
// 函數(shù)體內(nèi)的主邏輯
}
- 表達(dá)式計算。和其他很多解釋性語言一樣,JS同樣可以解釋運行由JS源代碼組成的字符串,并產(chǎn)生一個值。JS通過全局函數(shù)eval()來完成這個工作:eval("3+2") // =>5
eval()只有一個參數(shù).如果傳入的不是字符串,它直接返回這個參數(shù)。如果參數(shù)是字符串,它會把字符串當(dāng)成JS代碼進(jìn)行編譯(解析這段字符串),如果編譯失敗則拋出一個語法錯誤(SyntaxError)異常。如果編譯成功,則開始執(zhí)行這段代碼,并返回字符串中的最后一個表達(dá)式或語句的值,如果最后一個表達(dá)式或語句沒有值,則最終返回undefined。如果字符串拋出一個異常,這個異常將把該調(diào)用傳遞給eval() - typeof運算符。typeof是一元運算符,放在單個操作數(shù)的前邊,操作數(shù)可以是任何類型。返回值為表示操作數(shù)類型的一個字符串
任意值在typeof運算后的返回值
x | typeof x |
---|---|
undefined | "undefined" |
null | "object" |
true或false | "boolean" |
任意數(shù)字或NaN | "number" |
任意字符串 | "string" |
任意函數(shù) | "function" |
任意內(nèi)置函數(shù)(非對象) | "object" |
任意宿主對象 | 由編譯器各自實現(xiàn)的字符串,但不是"undefined"、"boolean"、"number"或"string" |
- delete運算符,是一元運算符,用來刪除對象屬性或者數(shù)組元素,它是用來做刪除操作的,不是用來返回一個值的,例如:
var o = {x: 1, y: 2}; // 定義一個對象
delete o.x; // 刪除一個屬性
"x" in o // false: 這個屬性在對象中不再存在了
var a = [1, 2, 3]; // 定義一個數(shù)組
delete a[2]; // 刪除最后一個數(shù)組元素
2 in a // false: 元素2在數(shù)組中已經(jīng)不存在了
a.length // =>3:注意數(shù)組長度并沒有變,盡管上一行代碼刪除了這個元素,但刪除操作留下了一個"洞"
(在該處設(shè)置了一個undefined的值),實際上并沒有修改數(shù)組的長度,因此a數(shù)組的長度仍是3
當(dāng)刪除一個屬性時,這個屬性將不再存在。讀取一個不存在的屬性將返回undefined,但是可以通過in運算符
來檢測這個屬性是否在對象中存在
- delete希望他的操作數(shù)是一個左值,如果它不是左值,那么delete將不進(jìn)行任何操作同時返回true。否則,delete將試圖刪除這個指定的左值。如果刪除成功,delete將返回true。然而并不是所有屬性都可以刪除,一些內(nèi)置核心和客戶端屬性是不能刪除的,用戶通過var語句聲明的變量不能刪除。同樣通過function語句定義的函數(shù)和函數(shù)參數(shù)也不能刪除(對變量、函數(shù)或函數(shù)參數(shù)進(jìn)行delete操作將拋出一個語法錯誤異常)。在嚴(yán)格模式下,delete刪除不可配置的屬性時會拋出一個類型錯誤異常。
var o = {x: 1, y: 2}; // 定義一個變量,初始化為對象
delete o.x; // 刪除一個對象屬性,返回true
typeof o.x; // 屬性不存在,返回"undefined"
delete o.x; // 刪除不存在的屬性,返回true
delete o; // 不能刪除通過var變量聲明的變量,返回false
// 在嚴(yán)格模式下,將拋出一個異常
delete 1; // 參數(shù)不是一個左值,返回true
this.x = 1; // 給全局對象定義一個屬性,這里沒有使用var
delete x; // 試圖刪除它,在非嚴(yán)格模式下返回false
// 在嚴(yán)格模式下會拋出異常,這是使用"delete this.x"來代替
x; // 運行時錯誤,沒有定義x
語句
- 全局變量是全局對象的屬性。然而和其他全局對象屬性不同的是,var聲明的變量無法通過delete刪除。如果var語句中的變量沒有指定初始化表達(dá)式,那么這個變量的值初始為undefined。
- 變量在聲明它們的腳本或者函數(shù)中都是有定義的,變量聲明語句會被“提前”至腳本或者函數(shù)的頂部,但是初始化的操作還是在原來var語句的位置執(zhí)行,在聲明語句之前變量的值是undefined。函數(shù)聲明語句創(chuàng)建的變量也是無法刪除的。
- for-in循環(huán)并不會遍歷對象的所有屬性,只有“可枚舉”的屬性才會遍歷到。由JS語言核心所定義的內(nèi)置方法就不是“可枚舉”的。如所有的對象都有方法toString(),但for-in循環(huán)并不枚舉toString()這個屬性。
- 標(biāo)簽語句--語句是可以添加標(biāo)簽的,標(biāo)簽是由語句前的標(biāo)識符和冒號組成:
identifier: statement - 函數(shù)調(diào)用是一種表達(dá)式,而所有表達(dá)式都有值。函數(shù)中的return語句既是指定函數(shù)調(diào)用后的返回值。return語句只能在函數(shù)內(nèi)出現(xiàn),如果不是的話會報語法錯誤。如果沒有return語句,則函數(shù)調(diào)用僅依次執(zhí)行函數(shù)體內(nèi)的每一條語句直到函數(shù)結(jié)束,最后返回調(diào)用程序。這種情況下,調(diào)用表達(dá)式的結(jié)果是undefined。
- try/catch/finally語句是JS的異常處理機制。其中try從句定義了需要處理的異常所在的代碼塊,catch語句跟隨在try從句之后,當(dāng)try塊內(nèi)某處發(fā)生了異常時,調(diào)用catch內(nèi)的代碼邏輯。catch從句后跟隨finally塊,后者中放置清理代碼,不管try塊中是否產(chǎn)生異常,finally塊內(nèi)的邏輯總是會執(zhí)行。盡管catch和finally都是可選的,但try從句需要至少二者之一與之組成完整的語句。try,catch和finally語句塊都需要花括號括起來,這里的花括號是必須的,即使從句中只有一條語句也不能省略花括號。
try/catch/finally的語法和使用目的
try {
// 通常來講,這里的代碼會從頭執(zhí)行到尾而不會產(chǎn)生任何問題
// 但有時會拋出一個異常,要么是由throw語句直接拋出異常
// 要么是通過調(diào)用一個方法間接拋出異常
} catch(e) {
// 當(dāng)且僅當(dāng)try語句拋出了異常,才會執(zhí)行這里的代碼
// 這里可以通過局部變量e來獲得對Error對象或者拋出的其他值的引用
// 這里的代碼塊可以基于某種原因處理這個異常,也可以忽略這個異常
// 還可以通過throw語句重新拋出異常
} finally {
// 不管try語句塊是否拋出了異常,這里的邏輯總會執(zhí)行,終止try語句塊的方式有:
// 1)正常終止,執(zhí)行完語句塊的最后一條語句
// 2)通過break、continue或return語句終止
// 3)拋出一個異常,異常被catch從句捕獲
// 4) 拋出一個異常,異常未被捕獲,繼續(xù)向上傳播
}
- with語句用于臨時擴展作用于鏈,它的語法如下:
with(object)
statement
這條語句將object添加到作用域鏈的頭部,然后執(zhí)行statement,最后把作用域鏈恢復(fù)到原始狀態(tài)。 - debugger語句(斷點器調(diào)試)和“use strict”(對腳本和函數(shù)使用應(yīng)用嚴(yán)格模式)