Javascript核心讀書有感之表達(dá)式和運算符
表達(dá)式是javascript中的一個短語,javascript解釋器會將其計算出一個結(jié)果。程序中常用量是最簡單的一類表達(dá)式就是變量。變量名也是一種簡單的表達(dá)式,它的值就是賦值給變量的值。
復(fù)雜的表達(dá)式是由簡單的表達(dá)式組成的。比如數(shù)組訪問表達(dá)式是由一個表示數(shù)組的表達(dá)式,方括號、一個整數(shù)表達(dá)式構(gòu)成。它們所組成新的表達(dá)式運算結(jié)果是該數(shù)組特定位置的元素值。同樣的函
數(shù)調(diào)用表達(dá)式由一個表示函數(shù)對象的表達(dá)式和0個多個參數(shù)表達(dá)式構(gòu)成。將簡單表達(dá)式組成復(fù)雜表達(dá)式最常用的方法就是運算符。
本章(本文)將講解所有javascript運算符。同時也講解不涉及運算符的表達(dá)式(比如訪問數(shù)組元素和函數(shù)調(diào)用),其語法和編程風(fēng)格和c語言都很相似。
1.元素表達(dá)式
最簡單的表達(dá)式是“原始表達(dá)式”,原始表達(dá)式是表達(dá)式的最小的單位--它們不包含其他表達(dá)式。javascript中的原始表達(dá)式包含常量或直接量。關(guān)鍵字和變量。
直接量是直接在程序中出現(xiàn)的常數(shù)值。它們看起來像:
1.23 //數(shù)字直接量
"hello" //字符串直接量
/pattern/ //正則表達(dá)式直接量
javascript中的一些保留字構(gòu)成了原始表達(dá)式
true //布爾值:真
false //假
null //返回一個值:空
this //返回"當(dāng)前"對象
通過第三章的學(xué)習(xí),和其它關(guān)鍵字不同,this并不是一個常量,他在程序的不同地方返回的值也不相同。this關(guān)鍵字經(jīng)常在面向?qū)ο缶幊讨谐霈F(xiàn)。this返回方格方法的對象。
最后,第三種原始表達(dá)式是變量
i //返回變量i的值
sum //返回sum的值
undefined //是全局變量,和null不同,它不是一個關(guān)鍵字
2.對象和數(shù)組的初始化表達(dá)式。
對象和數(shù)組初始化實際上是新創(chuàng)建的對象和數(shù)組,這些初始化的表達(dá)式有時候叫做“對象直接量”和“數(shù)組直接量”。然而和布爾直接量不同,他們不是原始表達(dá)式,因為他們所包含的成員或者元素都子表達(dá)式。
數(shù)組的初始化表達(dá)式語法非常簡單,我們以下開始
數(shù)組的初始化表達(dá)式是通過一對方括號和其內(nèi)由逗號隔開的列表構(gòu)成的,初始化結(jié)果是一個新創(chuàng)建的數(shù)組。數(shù)組的元素是逗號分隔表達(dá)式的值。
[] //一個空數(shù)組;[]內(nèi)留空即表示該數(shù)組沒有任何元素
[1+2,3+4] //有兩個元素的數(shù)組,第一個3,第二個是7
數(shù)組初始化表達(dá)式中的元素初始化表達(dá)式可以是數(shù)組初始化表達(dá)式。也就是說表達(dá)式是可以嵌套的
var mat = [[1,2,3],[4,5,6],[7,8,9]];
數(shù)組直接量中列表之間的元素可以省略,空位就會填充undefined.例如下面:
var a=[1,,,,5]
其中4個元素是undefined.數(shù)組直接量的結(jié)尾處留下逗號,這時不會創(chuàng)建一個新的值為undefined的元素。
對象初始化表達(dá)式和數(shù)組初始化表達(dá)式非常相似,只是方括號被花括號代替。并每個字表達(dá)式包含一個屬性名和非冒號作為前綴。
var p = {x: 2.1,y: -3} //一個擁有兩個屬性成員的對象
var q = {}; //空對象
q.x=2.1;q.y=-3; //q的屬性成員和p的一樣
對象直接量也可以嵌套,比如
var anh = {left:{x:2,y:3},
right:{x:4,y:5}}
javascript在計算對象初始化表達(dá)式的值時候,對象表達(dá)式都會各自計算一次,并且他們不必包含常數(shù)值:它們可以是任意javascript表達(dá)式。同樣,對象直接量中屬性的名稱可以是字符串而不是標(biāo)識符。(在在那行只能使用保留字或一些非法標(biāo)識符作為屬性名的時候非常有用)
var side = 1;
var square = {"left":{x:p.x,y:p.y},
'right':{x:p.x+side,y:p.y+side}}
第6 7章還會再次討論對象和數(shù)組的初始化表達(dá)式。
3.函數(shù)表達(dá)式
函數(shù)定義表達(dá)式定義一個javascript函數(shù)。表達(dá)式的值是這個新定義的函數(shù)。從某種意義上將,函數(shù)定義表達(dá)式可以成為函數(shù)直接量,函數(shù)表達(dá)式可稱為“函數(shù)直接量”,畢竟對象初始化表達(dá)式也稱為“對象直接量”。一個典型的函數(shù)定義表達(dá)式包含關(guān)鍵字function,其后是一對圓括號,括號以內(nèi)是逗號分隔的列表,列表包含0或多個標(biāo)識符(參數(shù)名)。然后跟隨花括號包裹的javascript代碼段(函數(shù)體).
var square = function(x){ return x*x};
函數(shù)定義表達(dá)式同樣可以包含函數(shù)的名字。函數(shù)也可以通過函數(shù)語句來定義,而不是函數(shù)表達(dá)式。更多內(nèi)容會在第八章描述。
4.屬性訪問表達(dá)式
屬性訪問表達(dá)式運算得到一個對象或者一個數(shù)組元素的值。javascript為屬性訪問定義了兩種方法。
expression . indentifier
expression [expression]
第一種寫法是一個表達(dá)式后跟隨一個句點和標(biāo)識符。表達(dá)式指定對象,標(biāo)識符則指定要訪問的屬性明川。
第二章寫法是使用方括號,方括號內(nèi)是一個表達(dá)式(這種方法適用于對象和數(shù)組)。第二個表達(dá)式指定要訪問的屬性的明川或者代表要訪問數(shù)組元素的索引。這里有一些具體的例子
o.x //=>1表達(dá)式o的x屬性
o.y.z //=>3 表達(dá)式o.y的z屬性
o.["x"] //=>1的對象o的x屬性
a[1] //=>4 表達(dá)式a索引為1的元素
a[2]["1"]//=>6 表達(dá)式a[2]中索引為1的元素
a[0].x //=>1: 表達(dá)式a[0]的x屬性
不管使用哪種形式的屬性訪問表達(dá)式,在"."和"["之前的表達(dá)式總會首先計算。如果計算結(jié)果為null或者undefined,表達(dá)式會拋出類型錯誤異常,因為這兩個值都不能包含任意屬性。如果運算結(jié)果不是對象或數(shù)組,javascript會將其轉(zhuǎn)換為對象(3章6節(jié)內(nèi)容)
雖然.identifier的寫法更加簡單,但需要注意的是,這種方式只適用于要訪問的屬性名稱是合法的標(biāo)識符。并且需要知道要訪問的屬性名字。如果屬性名稱是一個保留字或者包含空格和標(biāo)點符號,是一個數(shù)字(對于數(shù)組來說),則必須使用方括號的寫法。當(dāng)屬性名是通過運算符得出的值而不是固定值的時候,這時候必須使用方括號的寫法。(6章2節(jié)1小節(jié))
5.調(diào)運表達(dá)式
javascript中的調(diào)用表達(dá)式(invocation expression)是一種調(diào)用(或者執(zhí)行)函數(shù)或方法的語法表示。它以一個函數(shù)表達(dá)式開始,這個函數(shù)表達(dá)式指代了要調(diào)用的函數(shù)。函數(shù)表達(dá)式后跟隨一對圓括號,括號內(nèi)是一個以逗號隔開的參數(shù)列表。參數(shù)可以有0個也可以有多個。
f(0) //f是一個函數(shù)表達(dá)式:0是一個參數(shù)表達(dá)式。
Math.max(x,y,z) //Math.max是一個函數(shù);x,y和z是參數(shù)
a.sort() //a.sort()是一個函數(shù),它沒有參數(shù)。
當(dāng)調(diào)用表達(dá)式進(jìn)行求值的時候,首先計算函數(shù)表達(dá)式,然后計算參數(shù)表達(dá)式,得到一組參數(shù)值。如果函數(shù)表達(dá)式的值不是一個可調(diào)用的對象,則拋出一個類型錯誤異常.然后參數(shù)的值依次被賦值給形參,這些形參是定義函數(shù)時定義的。接下來執(zhí)行函數(shù)體。如果函數(shù)使用return語句給出一個返回值,那么這個返回值就是整個調(diào)用表達(dá)式的值。否則,調(diào)用表達(dá)式的值就是undefined.函數(shù)調(diào)用--包括形參表達(dá)式的個數(shù)和函數(shù)定義中實參的個數(shù)不匹配的時候運行的情況--的細(xì)節(jié)將會在第八章詳細(xì)說明。
任何一個調(diào)用表達(dá)式都包含一對圓括號和左圓括號之前的表達(dá)式,如果這個表達(dá)式是一個屬性訪問表達(dá)式,那么這個調(diào)用叫做“方法調(diào)用”(method invication)。在方法調(diào)用中執(zhí)行函數(shù)體的時候,作為屬性訪問主體的對象和數(shù)組便是其調(diào)用方法內(nèi)this的指向。這種特性使得在面向?qū)ο缶幊痰姆独?,函?shù)(其OO名稱為“方法”)可調(diào)用其宿主對象(第9章會有更多相關(guān)內(nèi)容)。
6.對象創(chuàng)建表達(dá)式
對象創(chuàng)建表達(dá)式(object creation expression)創(chuàng)建一個對象并調(diào)用一個函數(shù)(構(gòu)造函數(shù))來初始化對象的屬性。對象創(chuàng)建表達(dá)式和函數(shù)調(diào)用表達(dá)式非常類似,只是對象創(chuàng)建表達(dá)式之前多了一個關(guān)鍵字new:
new Object()
new Point(2,3)
如果對象創(chuàng)建表達(dá)式不需要傳入任何參數(shù)給構(gòu)造函數(shù)的話,那么這對圓括號是可以省略掉的,更多構(gòu)造函數(shù)的細(xì)節(jié)將在9章說明
new Object
new Point
7.運算符概述
javascript中的運算符用于算表表達(dá)式, 比較表達(dá)式, 邏輯表達(dá)式 ,賦值表達(dá)式等
需要注意的是大多運算符都是標(biāo)點符號來表示的,比如delete和instanceof.無論是關(guān)鍵字運算符還是符號運算符,所表示的運算符一樣都是正規(guī)運算符,他們的語法都非常言簡意賅。
下標(biāo)運算符的優(yōu)先級來排序的,前邊的運算符優(yōu)先級高于后邊的運算符優(yōu)先級。被水平華豐隔開的運算符具有不同的優(yōu)先級。
A表示運算符的結(jié)合性。
L從左至右或者R(從右至左)
標(biāo)題N的列表表示操作數(shù)的個數(shù)。
類型表示期望的操作數(shù)的類型,以及運算符的結(jié)果類型(在"→"符號之后)
運算符 | 操作 | A | N | 類型 |
++ | 前/后增量 | R | 1 | lval→num |
-- | 前后減量 | R | 1 | lval→num |
- | 求反 | R | 1 | num→num |
+ | 轉(zhuǎn)換為數(shù)字 | R | 1 | num→num |
~ | 按位求反 | R | 1 | int→int |
! | 邏輯非 | R | 1 | bool→bool |
delete | 刪除屬性 | R | 1 | lval→bool |
typeof | 檢測操作類型 | R | 1 | any→Str |
void | 返回undefined值 | R | 1 | any→undef |
* 、/、% | 乘 除 求余 | L | 2 | num,num→num |
+、- | 加,減 | L | 2 | num,num→num |
+ | 字符串連接 | L | 2 | str,str→str |
<< | 左移位 | L | 2 | int,int→int |
>> | 右移位 | L | 2 | int,int→int |
>>> | 無符號右移 |
L |
2 | int,int→int |
<,<=,>,>= | 比較數(shù)字順序 | L | 2 | num,num→bool |
<,<=,>,>= | 比較在字母中的順序 | L | 2 | str,str→bool |
instanceof | 測試對象類 | L | 2 | obj,func→bool |
in | 測試屬性是否存在 | L | 2 | str,obj→bool |
== | 判斷相等 | L | 2 | any,any→bool |
!= | 判斷不等 | L | 2 | any,any→bool |
=== | 判斷恒等 | L | 2 | any,any→bool |
!== | 判斷非恒等 | L | 2 | any,any→bool |
& | 按位與 | L | 2 | int,int→int |
^ | 按位異或 | L | 2 | int,int→int |
| | 按位或 | L | 2 | int,int→int |
&& | 邏輯與 | L | 2 | any,any→any |
|| | 邏輯或 | L | 2 | any,any→any |
?: | 條件運算符 | R | 3 | bool,any,any→any |
= | 變量賦值或?qū)ο髮傩再x值 | R | 2 | lval,any→any |
*= /= %= += -= &= ^= |= <<= >>= >>>= |
運算且賦值 | R | 2 | lval,any→any |
, |
忽略第一個操作數(shù), 返回第二個操作數(shù)。 |
L | 2 | any,any→any |
i.操作數(shù)的個數(shù)
運算符可以通過操作數(shù)的個數(shù)進(jìn)行分類。
javascript中的大多數(shù)運算符是二元運算符,將兩個表達(dá)式合并成一個稍微復(fù)雜的表達(dá)式。
javascript也支持一些一元運算符,它們將一個表達(dá)式轉(zhuǎn)換為另一個稍微復(fù)雜的表達(dá)式。表達(dá)式-x中的"-"運算符就是一個一元運算符。是將x求負(fù)值。
javascript支持一個三元運算符:條件判斷運算符“?:”,它將三個表達(dá)式合并為一個表達(dá)式
ii.操作數(shù)類型和結(jié)果類型
一些運算符可以用于任何數(shù)據(jù)類型,但仍然希望它們操作指定的類型的數(shù)據(jù)。
iii.左值
在表中的賦值運算符和其它少數(shù)運算符期望它們的操作數(shù)lval類型,左值是一個古老的術(shù)語。它是指“表達(dá)式只能出現(xiàn)在賦值運算符的左側(cè)”。javascript中,變量、對象屬性和數(shù)組元素均是左值。ECMAScript規(guī)范允許范圍內(nèi)置函數(shù)返回一個左值,但定義的函數(shù)則不能返回左值。
iiii.運算符的優(yōu)先級
在上表中,所示的運算符是按照優(yōu)先級從高到低排序的,每個水平分隔線內(nèi)一組運算符有相同的優(yōu)先級。運算符優(yōu)先級優(yōu)先控制著運算符的執(zhí)行順序。運算符高的(表頂)的執(zhí)行總是高于優(yōu)先級低的(表格的底部)運算符。
看如下表達(dá)式
w=x+y*z;
乘法運算符“*”比加法“+”具有更高的優(yōu)先級,所以乘法先執(zhí)行。然后,由于賦值運算符“=”具有最低優(yōu)先級。因此賦值操作是在右側(cè)的表達(dá)式計算出結(jié)果后進(jìn)行的。
運算符的優(yōu)先級可以使用園括號來從寫。以上表達(dá)式可以這樣寫。
w = (x + y) * z;
需要注意的是,屬性訪問表達(dá)式和調(diào)用表達(dá)式的優(yōu)先級要比表中的所有運算符都要高。
typeof my.Function[x](y)
盡管typeof是優(yōu)先級最高的運算符之一,但typeof也是在兩次屬性訪問和函數(shù)調(diào)用后執(zhí)行的。
事實上,如果你真的不確定你所使用的運算符優(yōu)先級,最簡單的方法就是使用園括號來強(qiáng)行指定運算次序。有些重要的規(guī)則則要熟記:乘法和除法高于加減法,賦值運算的優(yōu)先級非常低,通常是最后執(zhí)行的。
iiiiii.運算符的結(jié)合性
在本節(jié)表中,標(biāo)題為A的列說明了運算符的結(jié)核性。L指從左至右結(jié)合,R指從右至左結(jié)合。結(jié)核性指定了在多個具有同樣優(yōu)先級的運算符表達(dá)式中的運算順序。
例如,減法運算按照由左到右的執(zhí)行結(jié)合性。
w = x - y - z
和這段代碼一樣:
w = ((x - y) - z)
反過來講,下面這個表達(dá)式:
x = ~-y;
w = x = y = z;
q=a?b:c?d:e?f:g;
和這段代碼一模一樣
x=~(-y);
w=(x=(y=z));
q=a?b:(c?d:(e?f:g))
因為一元操作符、賦值和三元條件運算符都具有從右至左的結(jié)合性。
iiiiiii.運算順序
運算符的優(yōu)先級和結(jié)合性規(guī)定了它們在賦值的運算式中的運算順序,但并沒有規(guī)定字表達(dá)式的計算過程中的運算順序。javascript總是嚴(yán)格按照從左至右的順序計算表達(dá)式,例如:
在表達(dá)式 w=x+y*z 中,將首先計算表達(dá)式w,然后計算x、y和z,然后,y的值和z相乘,在加上x的值。最后將其表達(dá)式w所指代的變量或?qū)傩浴=o表達(dá)式添加園括號將會改變乘法,加法和賦值運算的關(guān)系。但從左至右的順序是不會改變的。
8.算術(shù)表達(dá)式
本節(jié)涵蓋了那些算術(shù)計算的運算符、以及對操作數(shù)的算術(shù)操作。乘法、除法和減法運算符非常簡單。加法運算單獨一節(jié),因為加法運算符可以操作字符串的連接,并且其類型轉(zhuǎn)換有些特殊。
基本的算術(shù)運算符是*、/、%、+、-。除了+加法,其它的運算符特別簡單,只是在必要的時候操作符轉(zhuǎn)化為數(shù)字而已,然后求積、商、余(模)和差。所有那些無法轉(zhuǎn)換為數(shù)字的操作都將轉(zhuǎn)換為NaN值。如果操作數(shù)(或者轉(zhuǎn)換結(jié)果)是NaN值,算術(shù)運算結(jié)果也是NaN
運算符“/”用第二個操作數(shù)來除以第一個操作數(shù),如果你使用過那些區(qū)分整數(shù)型和浮點數(shù)型的編程語言。那么用一個整數(shù)除以一個整數(shù)時,則希望得到的結(jié)果也是整數(shù)。在javascript中所有的數(shù)字都是浮點數(shù)型的,除法運算的結(jié)果也是浮點型。比如5/2結(jié)果是2.5,而不是2。除數(shù)為0的運算結(jié)果為正無窮大或負(fù)無窮大。而0/0的結(jié)果是NaN。所有這些運算均不會報錯。
運算符“%”計算的是第一個操作數(shù)對第二個操作數(shù)的模,換句話說,就是第一個操作數(shù)除以第二個操作鼠的余數(shù)。結(jié)果的符號和第一個操作鼠(被除數(shù))符號保持一致。例如5%2的結(jié)果為1,-5%2為-1。
求余運算符的操作數(shù)通常都是整數(shù),但也適用于浮點數(shù)。6.5%2.1結(jié)果是0.2。(0.19999999999999973)
i.“+”運算符
二元加法運算符“+”可以對兩個數(shù)字做加法,也可以做字符串連接操作:
1+2 //=> 3
"hello" + "" + "there" // =>"hello there"
"1"+"2" //=>"12"
當(dāng)兩個操作數(shù)都是數(shù)字或都是字符串的時候,計算結(jié)果是顯而易見的。然而對于其他情況來說,則要進(jìn)行一些必要的類型轉(zhuǎn)換。并且運算符的行為依賴于類型的轉(zhuǎn)換的結(jié)果。從技術(shù)上來講,加法操作符的行為表現(xiàn)為:
如果一個操作數(shù)是對象,則對象會遵循對象到原始值的轉(zhuǎn)換規(guī)則為原始類值(參照3章8節(jié)3小節(jié))。日期對對象toString()方法執(zhí)行轉(zhuǎn)換,其他對象則通過valueOf()方法執(zhí)行轉(zhuǎn)換(如果valueOf()方法返回一個原始值的話)。由于多數(shù)對象都不具備可用的valueOf()方法,因此他們會通過toString()方法來執(zhí)行抓換
在進(jìn)行了對象到原始值的轉(zhuǎn)換后,如果其中一個操作鼠是字符串的話,另一個操作數(shù)也會轉(zhuǎn)換為字符串。然后進(jìn)行字符串連接。
否則,兩個操作數(shù)都將轉(zhuǎn)換為數(shù)字(或者NaN),然后進(jìn)行加法操作。
這里有一些例子
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ù)字后做加法
2 + null //=>2 null轉(zhuǎn)換為0后做加法
2 + undefined //=>NaN undefined轉(zhuǎn)換為NaN做加法
最后,特別要注意的是。當(dāng)加號運算符合字符串一起使用時,要考慮加法對運算順序的影響。也就是說,運算結(jié)果是依賴于運算符的運算順序的,比如
1 + 2 + "bmice" //=> "3 bmice"
1 + (2 + "bmice") => "12bmice"
ii.一元運算符
一元運算符作用于一個單獨的操作數(shù)。并產(chǎn)生一個新值。在javascript中,一元運算符具有很高的優(yōu)先級,而且都是右結(jié)合。本節(jié)講述一元運算符(+,-,++和--),必要時,他們將操作轉(zhuǎn)換為數(shù)字。需要注意的的是+ -是一元運算符,也是二元運算符、
一元加法+
一元加法運算符把操作數(shù)數(shù)轉(zhuǎn)換為數(shù)字(或者NaN),并且返回這個轉(zhuǎn)換后的數(shù)字。如果操作數(shù)本身就是數(shù)字,則直接返回這個數(shù)字。
一元減法-
當(dāng)-號做一元運算符時,它會根據(jù)需要把操作數(shù)轉(zhuǎn)換為數(shù)字,然后改變運算結(jié)果的符號、
遞增++
遞增“++”運算符對其操作數(shù)進(jìn)行增量(+1)的操作,操作數(shù)一個左值(變量、數(shù)組元素或者對象屬性)。運算符將操作數(shù)轉(zhuǎn)換為數(shù)字。然后給數(shù)字加1、并將加1后的數(shù)值重新賦值給變量、數(shù)組元素或者對象屬性。
遞增++ 運算返回值依賴它對操作數(shù)的位置。
當(dāng)操作符在操作數(shù)數(shù)之前,稱為“前增量”(pre-increment)運算符,它對操作數(shù)進(jìn)行增量計算,并返回計算后的值。
當(dāng)操作符在操作數(shù)之后,稱為"后增量"(post-increment)運算符,它對操作數(shù)進(jìn)行增量計算,但返回為做增量計算的(unincremented)值。如
var i = 1,j = ++i //i和j的值都是2
var i = 1,j = i++; //i是2,j是1
需要注意的是,便打算++x并總和x=x+1完全一樣,“++”運算符從不進(jìn)行字符串連接操作,它總會將操作數(shù)轉(zhuǎn)換為數(shù)字并增1.如果x是字符串“1”,++x的結(jié)果就是數(shù)字2,而x+1是字符串"11"
遞減和遞增的操作方式是同樣的,它把操作數(shù)轉(zhuǎn)換為數(shù)組,然后減1.
iii.位運算符
位運算符可以對數(shù)字表示的二進(jìn)制數(shù)據(jù)進(jìn)行更低層級的按位運算。盡管它們不是傳統(tǒng)的純數(shù)學(xué)運算,但這里也歸類為算術(shù)運算符,因為他們作用于數(shù)值類型的操作并返回數(shù)字。這些運算符在javascript不常見。(此處不描述,詳情自行百度~-~)
9.關(guān)系表達(dá)式
本節(jié)講述javascript的關(guān)系運算符,關(guān)系運算符用于測試兩個值之間中的關(guān)系(相等、小于或“是...的屬性”),根據(jù)關(guān)系是否存在而返回true和false.關(guān)系表達(dá)式總是返回一個布爾值,通常在if while或者for語句(第五章)中使用關(guān)系表達(dá)式,以控制程序的執(zhí)行流程。
接下來幾節(jié)會講述相等和不等運算、比較運算符和javascript中其它兩個關(guān)系符in和instanceof
i相等和不等運算符
“==”和"==="運算符用于比較兩個值是否相等,兩個運算符允許任意類型的操作符。如果相等則返回true,否則返回false.“===”也稱為嚴(yán)格相等運算符(有時稱為恒等運算符),它用于檢測兩個操作數(shù)是否嚴(yán)格相等?!?=”運算符稱作相等運算符,它用來檢測兩個操作數(shù)是否相等,這里的相等定義寬松,可以允許進(jìn)行類型轉(zhuǎn)換。
javascript支持“=”,“==”,“===”運算符,你應(yīng)當(dāng)理解(賦值,相等,恒等)運算符之間的區(qū)別。并在編程中小心使用。為了減少混淆,應(yīng)該把“=”稱作“得到或賦值”,把“==”稱作“相等”,把“===”稱作“嚴(yán)格相等”。
“!=”和“!==”運算符規(guī)則是“==”,“===”運算符的求反,“!”是布爾非運算符,我們將“!=”,“!==”稱為不相等,不嚴(yán)格相等
javascript對象的比較是引用的比較,而不是值的比較。對象和本身是相等的,但和人和對象都不相等。如果兩個對象具有相同數(shù)量的屬性,相同的屬性名和值,它們依然是不相等的。相應(yīng)位置的數(shù)組元素是相等的兩個數(shù)組也是不相等的。
嚴(yán)格相等運算符"==="首先計算操作數(shù)的值,然后比較這兩個值,比較過程沒有任何類型轉(zhuǎn)換。
如果兩個值類型不想同,則它們不相等
如果兩個值都是null或者undefined,則它們不相等
如果兩個值都是布爾值true或者false, 則它們相等
如果其中一個值是NaN,或者兩個值都是NaN ,則它們不相等,NaN和其它值都是不相等的,包括它本身。
如果兩個值為數(shù)字且相等,則它們相等。如果一個值為0,令一個值為-0,則它們同樣相等。
如果兩個值為字符串,并且所含對應(yīng)位上的16位數(shù)(參照3章2節(jié))完全相等,則它們相等。如果他們的長度或內(nèi)容不同,則不相等。兩個字符串可能函數(shù)完全一樣并且所顯示出的字符也一樣,但具有不用編碼的16位值,javascript并不對Unicode進(jìn)行標(biāo)準(zhǔn)轉(zhuǎn)換,因此這樣的字符串通過"==="和"=="運算符的比較結(jié)果也不相等。第三部分的String.localeCompare()提供了另外一種比較字符串的方法。
如果兩個引用值指向同一個對象,數(shù)組或函數(shù),則它們是相等的。如果指向不同的對象,則它們是不等的,盡管兩個對象有完全相同的屬性。
相等運算符"=="和恒等運算符相似,但相等運算符比較并不嚴(yán)格。如果兩個數(shù)不是同一類型,那么相等運算符會嘗試進(jìn)行一些類型轉(zhuǎn)換,然后進(jìn)行比較。
如果兩個操作類型相同,則和上文相等運算符的比較規(guī)則一樣。如果嚴(yán)格相等,那么比較結(jié)果相等。如果他們不嚴(yán)格相等,則比較結(jié)果不相等。
如果兩個操作類型不同,“==”相等操作符也會認(rèn)為它們相等。檢測相等會遵循如下的規(guī)則和類型轉(zhuǎn)換:
如果一個類型是null,令一個是undefined,則它們相等
如果一個值是數(shù)字,另一個是字符串,先將字符串轉(zhuǎn)換為數(shù)字,然后使用轉(zhuǎn)換后的值進(jìn)行比較。
如果一個值是true,則將其轉(zhuǎn)換為1再進(jìn)行比較,如果一個值是false,則轉(zhuǎn)換為0比較。
如果一個值是對象,另一個值是數(shù)字或字符串,則使用3章8節(jié)3小節(jié)的方法的轉(zhuǎn)換規(guī)則將對象轉(zhuǎn)換為原始值,然后進(jìn)行比較。對象通過toString()方法或者valueOf()方法轉(zhuǎn)換為原始值。javascript語言核心的內(nèi)置類首先嘗試使用valueOf()再嘗試使用toString(),除了日期類,日期類只能通過toString()轉(zhuǎn)換。那些不是javascript 語言核心中的對象則通過實現(xiàn)中定義的方法轉(zhuǎn)換為原始值。
其它不同類型之間的比較均不相等
這里有一個判斷相等的小例子
"1" == true
這個表達(dá)式的結(jié)果為true,這表明完全不同類型的值比較結(jié)果為相等。布爾值true首先轉(zhuǎn)換為數(shù)字1 ,然后再執(zhí)行比較。接下來字符串“1”也會轉(zhuǎn)換為數(shù)字1 ,因為兩個數(shù)字的值相等,因此結(jié)果為true.
ii.比較運算符
小于(<)
如果第一個操作數(shù)小于第二個操作數(shù),則“<”運算結(jié)果我true,否則為false
小于等于(<=)
大于(>)
大于等于(>=)
....(不詳細(xì)介紹含義)
比較操作符的操作數(shù)可能是任意類型。然而只有數(shù)字和字符串才能真正執(zhí)行比較操作符,因此,那些不是數(shù)字和字符串的操作數(shù)都將進(jìn)行類型轉(zhuǎn)換。類型轉(zhuǎn)換規(guī)則如下:
如果操作數(shù)為對象,則按照3章8節(jié)3小節(jié)處鎖描述的轉(zhuǎn)換規(guī)則轉(zhuǎn)換為原始值:如果valueOf()返回一個原始值,那么直接使用這個原始值。否則使用toString() 的轉(zhuǎn)換結(jié)果進(jìn)行比較。
在對轉(zhuǎn)換為原始值之后,如果兩個操作數(shù)都是字符串,那么將依字母表的順序?qū)蓚€字符串進(jìn)行比較,這里提到的“字母表順序”是組成這兩個字符串的16位Unicode字符的索引順序。
在對象轉(zhuǎn)換為原始值之后,如果至少一個操作數(shù)不去是字符串,那么兩個操作數(shù)都將為數(shù)字進(jìn)行數(shù)值的比較。0和-0是相等的。Infinty壁其它任何數(shù)字都大(除了infinty本身),-infinty比任何數(shù)字都小(除了它自己本身。)如果一個操作數(shù)(或轉(zhuǎn)換后)為NaN,那么比較符總是返回false
對于數(shù)字和字符串操作符來說,加號運算符和比較運算符的行為有所不同 ,前者更偏愛字符串,如果它的其中一個操作數(shù)是字符串的話,則進(jìn)行字符串連接操作。而比較運算符則更偏愛數(shù)字,只有在兩個操作數(shù)都是字符串串的時候。才會進(jìn)行字符串的比較。
1 + 2 //=>3 加法,結(jié)果為3
"1" + "2" //字符串連接,結(jié)果為"12"
"1" + 2 //字符串連接,2轉(zhuǎn)換為"2",結(jié)果"12"
11 < 3 //數(shù)字比較,結(jié)果true
"11" < "3" //字符串比較,結(jié)果為true
"11" < 3 //數(shù)字的比較,“11”轉(zhuǎn)換為11,結(jié)果為true
"one" < 3 //數(shù)字比較,"one"轉(zhuǎn)換為NaN,結(jié)果為falase
最后需要注意的是,“<=”和“>=”運算符在判斷相等的時候,并不依賴相等運算符和和嚴(yán)格相等運算比較規(guī)則。相反,小于等于運算符芝是簡單的“不大于”,大于等于運算只是“不小于”。只有一個例外,的那個一個操作數(shù)(后轉(zhuǎn)換后)是NaN的時候,所有4個比較運算符均會返回fasle.
iii.in運算符
in運算符希望它的左操作數(shù)是一個字符串或者可以轉(zhuǎn)換為字符串,希望它的右側(cè)是一個對象。如果右側(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, 8]
"0" in data //=>true 數(shù)組包含0
1 in data //=>true 數(shù)字轉(zhuǎn)換為字符串
3 in data //=>fase 沒有索引為3的元素
iiii.instanceof運算符
instanceof運算符希望左操作符為一個對象,右操作數(shù)標(biāo)示對象的類。如果左側(cè)的對象是右側(cè)類的實例,則表達(dá)式返回true;負(fù)責(zé)返回false.第9章將會講到。javascript對象的類是通過初始化他們的構(gòu)造函數(shù)的來定義的。這樣的話,instanceof的右操作數(shù)應(yīng)當(dāng)是一個函數(shù)。比如:
var d = new Date(); //構(gòu)造一個新對象
d instanceof Date; //計算結(jié)果為true, d是Date() 創(chuàng)建的
d instanceof Object //計算結(jié)果為true ,所有的對象都是Object的實例
d instanceof Number //計算結(jié)果為 false,d不是一個Number對象
var a = [1,2,3] //數(shù)組直接量創(chuàng)建數(shù)組
a instanceof Array //計算結(jié)果true a為數(shù)組
a instanceof Object //true 所有的數(shù)組都是對象
a instanceof RegExp //fasle 數(shù)組不是正則表達(dá)式
需要注意的是,所有對象都是Object的實例。當(dāng)通過instanceof盤對一個對象是否為一個類的實例的時候,這個判斷也叫“父類”(superclass)的檢測,如果instanceof的左側(cè)操作對象不是對象的話,instanceof返回false。如果右側(cè)操作不是函數(shù),則拋出類型錯誤的異常。
為了理解instanceof運算符是如何工作的,必須首先理解“原型類”(prototype chain),原型鏈作為javascript的繼承機(jī)制,將在6章2節(jié)2小節(jié)詳細(xì)描述。
為了計算表達(dá)式o instanceof f ,javascript筆仙首先計算f.prototyoe,然后在原型鏈中查詢o,如果找到,那么o是f(或者f的父類)的一個實例,那么返回true。反之false
10.邏輯表達(dá)式
邏輯運算符"&&"、“||”、“!”是對操作進(jìn)行布爾算術(shù)運算,經(jīng)常和關(guān)系運算符一起配合使用,邏輯運算符將多個關(guān)系表達(dá)式組合起來組成一個更復(fù)雜的表達(dá)式。
i.邏輯與
"&&"運算符可以從三個不同的層次進(jìn)行理解。最簡單一層理解是,當(dāng)操作數(shù)都是布爾值是,“&&”對兩個布爾值執(zhí)行布爾與(AND)操作,只有在第一個操作數(shù)和第二個操作數(shù)都是true的時候,它才返回true.如果其中有一個操作數(shù)為false.則它返回false.
"&&"長用來連接兩個關(guān)系表達(dá)式
x == 0 && y == 0; //只有在x和y都是0時,才返回true
關(guān)系表達(dá)式總是返回true或false,因此當(dāng)這樣使用的時候,“&&”本身也返回true或 false。關(guān)系運算符的優(yōu)先級要比"&&"(和“||”)要高,因此類似這種表達(dá)式可以放心地書寫,而不用補(bǔ)充園括號。
"&&"操作數(shù)并不一定是布爾值,回想一下,有些值是可以當(dāng)做“真值”和“假值”的。(如3章3節(jié),假值是:false null undefined 0 -0 NaN和"",所有和其它的值包括所有的對象都是真值)。對“&&”第二層理解是,“&&”是可以對真值和假值進(jìn)行布爾與(AND)操作。如果兩個操作數(shù)都是真值的,則那么返回一個真值;否則,至少一個操作數(shù)是假值的。javascript中在任何使用布爾值的地方的時候,表達(dá)式語句都會將其當(dāng)做真值或假值來對待,因此實際上“&&”并不總是返回true和false.但也并無大礙。
需要注意的是,上文提到了運算符返回“真值”和“假值”,但并沒說說明這個“真值”或者“假值”到底是什么值,為此我們深入討論對“&&”第三層的理解。運算符首先計算左操作數(shù)的值,即首先計算“&&”左側(cè)的表達(dá)式,如果計算結(jié)果是假值,那么整個表達(dá)式的結(jié)果一定是假值,因此“&&”這時簡單的返回左操作的值,而并不會對右邊的操作數(shù)進(jìn)行計算。
var o = {
x: 1
};
var p = null;
o && o.x; //=>1 : 1:0是真值,因此返回值是o.x
p && p.x //= null :p是假值,因此將其返回,而并不計算p.x
這對于理解“&&”可能不計算右操作數(shù)的情況至關(guān)重要,在上述代碼中,變量P的值是null,而如果計算p.x的話則會拋出一個異常錯誤,因此,只有p為真值(不能是null或undefined)的情況下才計算p.x
"&&"的行為有時候被稱為“短路”(short circuiting),我們經(jīng)常能看到很多代碼利用了這一也行來有條件的執(zhí)行代碼。例如下面的兩條代碼是等價的
if (a == b) stop(); //只有a==b時才能調(diào)運stop()
(a == b) && stop(); //同上
一般來講,當(dāng)“&&”右側(cè)的表達(dá)式具有副作用的時候(賦值,遞增,遞減和函數(shù)調(diào)用表達(dá)式)要格外小心。因為這些帶有副作用的表達(dá)式的執(zhí)行時候,依賴于左操作鼠的計算結(jié)果。
盡管“&&”可以按照第二層和第三層的理解進(jìn)行一些復(fù)雜的表達(dá)式運算,但大多數(shù)的情況下,“&&”僅用來對真值和假值的做布爾計算。
ii.邏輯或(||)
"||"運算符對兩個操作數(shù)做布爾或(OR)運算。如果其中一個為真值,則返回真值,兩個操作數(shù)都為假值,返回假值。
盡管“||”運算符大多情況下只是做簡單的布爾或(OR)運算,和“&&”一樣,也具備一些更復(fù)雜的行為,它首先計算第一個操作數(shù)的值,也就是說回首先計算左側(cè)的表達(dá)式,如果計算結(jié)果為真,則返回真值,否則,再計算第二個值。
和“&&”一樣,用于應(yīng)該避免右操作數(shù)包含一些具有副作用的表達(dá)式,除非你目地明確在右側(cè)使用帶副作用的表達(dá)式,而有可能不會計算右側(cè)的表達(dá)式。
這個運算符最常用的方式是用來從一組備選的表達(dá)中選取第一個真值的表達(dá)式。
//如果max_width已經(jīng)定義了,則直接使用它。賦值在preferences對象中查找max_width
//如果沒有定義它,則使用一個寫死的常量。
var max =max_width || preferences.max_windth || 500;
這種貫用法通常在函數(shù)體內(nèi),用來給參數(shù)提供默認(rèn)值。
//將o成功的屬性復(fù)制到p中,并返回p
function copy(o, p) {
p = p || {}; //如果向參數(shù)p沒有傳入任何對象,則使用一個新創(chuàng)建對象。
//函數(shù)體內(nèi)的主邏輯
iii.邏輯非(!)
"!"運算符是一元運算符,它放置在一個單獨操作數(shù)之前。它的目的是將操作數(shù)的布爾值求反。
和"&&"、"||"運算符不同,“!”運算符首先將其操作數(shù)轉(zhuǎn)換為布爾值(參考第三章的講訴規(guī)則),然后再對布爾值求反。也就是"!"總是返回true和 false。并且,可以通過使用兩次邏輯非運算來得到一個值的布爾值:(!!x,參照第三章第八節(jié)第2小節(jié))
“!”具有很高的優(yōu)先級,并且和操作數(shù)緊密的綁在一起,如果希望對p && q,則需要園括號!(p && q)。如下代碼:
!(p && q) === !p || !q
!(p || q) === !p && !q
對于p和q取任何值,這兩個表達(dá)式永遠(yuǎn)成立。
11.賦值表達(dá)式
javascript使用"="運算符給變量或者屬性來賦值,例如:
i = 0 //將變量i設(shè)置為0
o.x = 1 //將對象o的屬性x 設(shè)置為1
“=”運算符希望它的左操作數(shù)為一個左值:一個變量或者對象屬性(或數(shù)組元素),它的右操作鼠可以是任意的類型的任意值。賦值表達(dá)式的值就是右操作數(shù)的值。賦值表達(dá)式的副作用是,右操作數(shù)的值賦值給左側(cè)的變量或?qū)ο髮傩?。這樣的話,后續(xù)對這個變量和對象的屬性的引用都將得到這個值。
盡管賦值表達(dá)式的值非常簡單,但有時候會看到一些復(fù)雜表達(dá)式包含賦值表達(dá)式的情況。例如:將賦值和檢測操作放在一個表達(dá)式中:
(a = b) == 0
如果這樣的話,應(yīng)該清楚地知道"="和"=="區(qū)別!,需要注意的是,“=”有非常低的優(yōu)先級,通常在一個較長的表達(dá)式中用到一條賦值語句時,需要補(bǔ)充園括號以保障正確的運算順序。
賦值操作符的結(jié)合性是從右至左,也就是說,一個表達(dá)式中出現(xiàn)了多個賦值運算符,運算順序也從右至左,因此,可以通過以下方式對多個變量賦值。
i=j=k=0; //把三個變量初始化為0
帶操作的賦值運算:
除了常規(guī)的賦值運算外,javascript還支持需要其他的賦值運算符,這些運算符將賦值運算符合其他的運算符連接起來。提供一種更為快捷的運算方式。例如+=運算符執(zhí)行的是加法運算符和賦值操作,下面的表達(dá)式:
total += salaes_tax;
和下面的表達(dá)式等價的
total = total + salaes_tax
運算符“+=”可以作用于數(shù)字或字符串,如果其操作是數(shù)字,它將執(zhí)行加法運算和賦值操作;如果是字符串,他就執(zhí)行字符串的連接和賦值操作。
此類型的運算符還包括,"-=","*=","&="等,如下表賦值運算符
運算符 示例 等價于
+= a+=b a=a+b
-= a-=b a=a-b
*= a*=b a=a*b
/= a/=b a=a/b
%= a%=b a=a%b
<<= a<<=b a=a<<b
>>= a>>=b a=a>>b
>>>= a>>>=b a=a>>>b
&= a&=b a=a&b
|= a|=b a=a|b
^= a^=b a=a^b
大多數(shù)情況下,表達(dá)式為
a op =b
這里的op代表一個運算符,這個表達(dá)式等價于
a =a op b
在第一行中,表達(dá)式a計算了一次,在第二行中,表達(dá)式a計算了兩次。
只有 a包含具有副作用的表達(dá)式(比如函數(shù)調(diào)用和賦值操作)的時候,兩者才不等價。如下兩個表達(dá)式不等價
data[i++] *= 2;
data[i++] = data[i++] * 2
12.表達(dá)式計算
和很多解釋性語言一樣,javascript同樣可以解釋運行由javascript源代碼組成的字符串,并產(chǎn)生一個值。javascript通過全局函數(shù)eval()來完成這個工作。
eval("3+2") //=>5
動態(tài)判斷源代碼中的字符串是一種強(qiáng)大語言的特性,幾乎沒有必要在實際中應(yīng)用。如果你使用了eval(),你應(yīng)該仔細(xì)考慮真的需要它。
下面降價eval()基礎(chǔ)用法,并介紹兩種嚴(yán)格使用它的方法,從代碼優(yōu)化的角度來講,這兩種方法對原有的代碼影響是最小的。
i.eval(eval()是一個函數(shù),但由于它已經(jīng)被當(dāng)做運算符來對待了。)
eval()只有一個參數(shù),如果傳入的參數(shù)不是字符串,它直接返回這個參數(shù)。如果參數(shù)是字符串,它會把字符串當(dāng)成javascript進(jìn)行編譯(parse),如果編譯失敗則拋出一個語法錯誤(SyntaxError)。如果編譯成功,則開始執(zhí)行這段代碼,并返回字符串中最后一個表達(dá)式或語句的值,如果最后一個表達(dá)式?jīng)]有語句或者值,則最終返回undefined。如果字符串拋出一個異常,這個異常把該調(diào)用的傳給eval()
關(guān)于eveal()最重要的是,它使用了調(diào)用它的變量作用域環(huán)境,也就是說,它查找變量的值和定義新變量和函數(shù)的操作和局部的代碼作用域中的代碼一樣。如果一個函數(shù)定義了一個局部變量x,然后調(diào)用了eval("x"),它會返回局部變量的值。如果它調(diào)用eval("x=1"),它會改變局部變量的值。如果函數(shù)調(diào)用了eval("var y=3;")它聲明一個新的局部變量y。同樣的,一個函數(shù)可以通過如下代碼聲明一個局部函數(shù):
eval("function f(){return x+1;}");
如果最頂層的代碼中調(diào)用了eval()。當(dāng)然它會作用于全局變量和全局函數(shù)。
ii.全局eval()
eval()具有改變局部變量的能力,這對javascript優(yōu)化器來說,是一個很大的問題,然而作為一種權(quán)宜之計,javascript征對那行調(diào)用了eval()函數(shù)所做的優(yōu)化并不多。但當(dāng)腳本定義了一個別名,并且用令一個名稱來調(diào)用它,javascript解釋器又如何工作呢,為了javascript解釋器更加簡化。ECMAScipt3標(biāo)準(zhǔn)規(guī)定了任何解釋器都不允許對eval()賦予別名。如果eval()使用別的別名來調(diào)用的話,則會拋出EvalError異常。
實際上,大多數(shù)的實現(xiàn)并不是這樣做的。當(dāng)通過別名調(diào)用時,eval()會將其字符串當(dāng)成頂層的全局代碼來執(zhí)行。執(zhí)行代碼可能會定義新的全局變量和全局函數(shù)。執(zhí)行的代碼可能會定義新的全局變量和全局函數(shù),或者給全局變量賦值。但卻不能修改或修改主調(diào)函數(shù)中的局部變量,因此這不會影響到函數(shù)內(nèi)的代碼優(yōu)化。
ECMAScript5是反對使用EvalError的,并且規(guī)范了eval()的行為。“直接的eval”,當(dāng)直接使用非限定的“eval”名稱,來調(diào)用eval()函數(shù)時,它總共是在它的上下文作用域內(nèi)支線。其它間接調(diào)用則使用全局函數(shù)為其上下文作用域。并且無法讀、寫、定義局部變量和函數(shù)。下面有一段代碼實例:
var geval = eval; //使用別名調(diào)用eval將是全局eval
var x = "global",
y = "global"; //兩個全局變量
function f() { //函數(shù)內(nèi)執(zhí)行的局部eval
var x = "local" //定于局部變量
eval("x += 'changed';"); //直接eval更改了局部變量的
return x; //返回更改后的局部變量
}
function g() { //這個函數(shù)執(zhí)行了全局eval
var y = "local" //定義了局部變量
geval("y += 'changed';"); //間接改變了局部變量的值
return y; //返回未更改的局部變量
}
console.log(f(), x); //更改了局部變量,輸出local changed global
console.log(g(), y); //更改了全局變量,輸出local globalchanged
13.其它運算符。
javascript支持很多其它各種各樣的運算符。
i.條件運算符(?:)
條件運算符是javascript中的唯一一個三元運算符。通常這個運算符寫成"?:",這個運算符擁有三哥操作數(shù),第一個操作數(shù)在"?"之前,第二個操作數(shù)在“?”和":"之間。第三個操作數(shù)早在":"之后,例如
x > 0 ? x : -x; //求x的絕對值
條件運算符的操作數(shù)可以是任意類型。第一個操作數(shù)當(dāng)成布爾值,如果它是真值,那么將計算第二個操作數(shù),并返回計算結(jié)果。賦值如果第一個值操作數(shù)是假值,那么將計算第三個操作數(shù)。并返回計算結(jié)果。第二個和第三個操作數(shù)總會計算其中之一。不可能兩者同時進(jìn)行。其實使用if語句也達(dá)到同樣的效果(5.4.1),“?:”運算符只是提供了一種簡寫形式。這里是一個"?:"的典型使用場景,判斷一個變量是否有定義,如果有定義則使用它,如果無定義,則使用一個默認(rèn)值。
grett = "hello" + (username ? username : "three");
和以下的代碼是等價的,但上面的更加簡潔
grett = "hello";
if (username)
grett += username;
else
grett + "three"
ii.typeof()運算符
typeof是一元運算符,放在單個操作數(shù)前面,操作數(shù)可以是任何類型,返回值表示操作類型的一個字符串。
x __ typeof x
undefined __ "undefined"
null __ "object"
ture或false __"boolean"
任意數(shù)字或NaN __ "Number"
任意字符串 __ "String"
任意函數(shù) __ "function"
任意內(nèi)容對象(非函數(shù))__ "object"
任意宿主對象 __ 由編譯器各自實現(xiàn)的字符串,但不是"undefined" "boolean" "number" "string"
typeof最常用的用法寫在表達(dá)式中們就像這樣
(typeof value == "string") ? "" + value + "":value;
typeof運算符同樣在swith語句中(5.4.3)非常有用,需要注意的是,typeof運算可以帶上園括號。這樣讓typeof看起來像一個函數(shù)名,而非關(guān)鍵字
typeof(i)
iii.delete運算符
delete是一元操作符,它用來刪除對象的屬性或者數(shù)組的元素。就像賦值、遞增、遞減運算符一樣。delete也是具有副作用的。它是用來做刪除操作的。不是用來返回一個值的。
var o = {
x: 1,
y: 2
}
delete o.x;
"x" in o; //=>false
var a = [1, 2, 3];
delete a[2]; // 刪除數(shù)組中最后一個元素
2 in a; //=> false 元素2已經(jīng)在數(shù)組中不存在了
a.length; //=>3,注意,數(shù)組長度并沒有改變,盡管上一行刪除了這個元素,但刪除操作留下了一個洞。實際上并沒有修改數(shù)組的長度,因此a的長度仍然為3
需要注意的是,刪除屬性或刪除數(shù)組元素不僅僅設(shè)置了一個undefined值,當(dāng)刪除一個屬性時,這個屬性不復(fù)存在。讀取一個不存在的值將會返回undefined.關(guān)于delete刪除還有嚴(yán)格模式下的一些情況,需要學(xué)習(xí)的人自己試驗,這里給一些例子。
var o = {x: 1,y: 2};
delete o.x; //刪除一個對象屬性,返回true
typeof o.x; //屬性不存在,返回"undefined"
delete o.x; //刪除不存在的屬性,返回true;
delete o; //不能刪除通過var關(guān)鍵字聲明的變量,返回false
delete 1; //參數(shù)不是一個左值。
this.x = 1;// 給全局定義一個屬性,這里沒有使用var
delete x ; //試圖刪除它,在非嚴(yán)格模式下返回true
//在嚴(yán)格模式下回拋出異常,這時使用"delete this.x"來代替
x; //運行時出錯,沒有定義x
6章第三節(jié)還有關(guān)于delete的討論。
iii.void運算符。
void是一元運算符,在出現(xiàn)操作數(shù)之前,操作數(shù)可以是任何類型。這個運算符并不是經(jīng)常使用:操作數(shù)會照常計算,但會忽略計算結(jié)果并返回undefined。由于void會忽略操作數(shù)的值,因此在操作數(shù)具有副作用時使用void來程序更有意義。
這個最常用的帶客戶端url.在url寫帶有副作用的表達(dá)式,而void則讓瀏覽器不顯示在這個表達(dá)式的運算結(jié)果。
<a href="javascript:void window.open();">new</a>
iiii.逗號運算符。(,)
逗號運算符是二元運算符,它的操作數(shù)可以是任意類型。它首先計算左操作數(shù),然后計算右操作數(shù)。
i = 0, j = 1, k = 2;
它和下面的代碼基本上等價的
i = 0; j = 1; k = 2;
總是會計算左側(cè)的表達(dá)式,但計算結(jié)果忽略掉,也就是說,只有左側(cè)表達(dá)式具有副作用,才會使用逗號運算讓代碼變得更通暢。逗號運算符最常用的場景是for循環(huán)中,這個for循環(huán)通常有多個循環(huán)變量。
//for循環(huán)中的第一個逗號是var語句的一部分
//第二個逗號是逗號運算符
//它將兩個表達(dá)式(i++和j++)放在一條(for循環(huán)中)語句中
for (var i = 0, j = 10; i < j; i++, j--);
console.log(i + j);
相關(guān)文章
JavaScript 判斷判斷某個對象是Object還是一個Array
在開發(fā)中,我們經(jīng)常需要判斷某個對象是否為數(shù)組類型,在Js中檢測對象類型的常見方法都有哪些呢?2010-01-01JavaScript 中的日期和時間及表示標(biāo)準(zhǔn)介紹
本文為大家詳細(xì)介紹下時間標(biāo)準(zhǔn)指的是什么?UCT和GMT 的概念、關(guān)聯(lián)和區(qū)別?以及時間表示標(biāo)準(zhǔn)有哪些?感興趣的朋友可以參考下2013-08-08Javascript學(xué)習(xí)筆記9 prototype封裝繼承
在上文中,我利用prototype的原理做了一個封裝的New,然后我就想到,我是否可以用prototype的原理進(jìn)一步封裝面向?qū)ο蟮囊恍┗咎卣髂兀勘热缋^承。2010-01-01詳解JavaScript中g(shù)etFullYear()方法的使用
這篇文章主要介紹了詳解JavaScript中g(shù)etFullYear()方法的使用,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06