表達(dá)式和運(yùn)算符
- 程序中最簡單的表達(dá)式就是蝗茁,程序中的常量
- 變量名也是一種簡單的表達(dá)式
- 復(fù)雜的表達(dá)式是由簡單的表達(dá)式組成的
- 函數(shù)調(diào)用表達(dá)式是由函數(shù)對象的表達(dá)式和0個或多個參數(shù)表達(dá)式構(gòu)成
- 可以使用運(yùn)算符來將簡單的表達(dá)式來組合成復(fù)雜的表達(dá)式
原始表達(dá)式
“原始表達(dá)式”寻咒,說簡單點(diǎn)就是最簡單的表達(dá)式哮翘,并且不再包含其他表達(dá)式
js中原始表達(dá)式有以下:
- 常量
- 直接量
- 關(guān)鍵字
- 變量
栗子:
//直接量
1.23 // 數(shù)字直接量
"hello" // 字符串直接量
/pattern/ // 正則表達(dá)式直接
//保留字
true
false
null // 返回空
this // 返回“當(dāng)前對象”
//變量
i // 返回i的值
sum // 返回sum的值
undefined // undefined是全局變量,和null不同毛秘,不是一個關(guān)鍵字
對象和數(shù)組的初始化表達(dá)式
對象和數(shù)組的初始化表達(dá)式實(shí)際上是一個新創(chuàng)建的對象和數(shù)組饭寺,并不是原始表達(dá)式
數(shù)組初始化表達(dá)式
栗子:
[] //空數(shù)組
[1+2,3+4] // 2個元素數(shù)組 [3,7]
var matrix = [[1,2],[3,4]] // 數(shù)組可嵌套
js對數(shù)組初始化表達(dá)式進(jìn)行求值時候阻课,數(shù)組表達(dá)式中的所有元素表達(dá)式也會各自計算一次
數(shù)組直接量的元素表達(dá)式在逗號之間元素可以省略,空位默認(rèn)填充undefined艰匙。
var array = [1,,3] // 數(shù)組包含3個元素限煞。[1,undefined,3]
但是列表結(jié)尾處可以留下單個逗號,這時不會創(chuàng)建新的undefined元素
對象初始化表達(dá)式
對象初始化表達(dá)式與數(shù)組初始化表達(dá)式非常接近员凝,將[]替換成{},每個子表達(dá)式都包含一個屬性名和冒號為前綴
栗子
var p = { x:2, y:3 }; // 帶2個屬性的對象p
var q = {}; // 空對象
q.x = 2; q.y =3; // q的屬性成員與p一致
對象直接量也是允許嵌套的
var rect = {
upLeft: { x:2, y:3},
bottomRight: { x:4, y:1}
};
js求對象初始化表達(dá)式時候署驻,對象元素表達(dá)式也會各自都計算一次,并且元素表達(dá)式不必包含常數(shù)值健霹,可以是
任意的js表達(dá)式旺上。
對象直接量中屬性的名字可以是字符串而不是標(biāo)示符
>```
var side = 1;
var square = {
"upLeft": { x: p.x, y: p.y},
"bottomRight": {x: p.x+side, y: p.y+side}
};
函數(shù)表達(dá)式
函數(shù)定義表達(dá)式定義一個js函數(shù),表達(dá)式的值是這個新定義的函數(shù)糖埋。如下
var square = function (x){
return x * x;
};
屬性訪問表達(dá)式
屬性訪問表達(dá)式得到一個對象屬性或一個數(shù)組元素的值宣吱。主要有.
和[]
兩種形式
栗子:
var o = { x:1, y:{ z:3 } };
var a = [o, 4, [5,6]];
o.x // =>1 表達(dá)式o的x屬性
o.y.z // =>3 表達(dá)式o.y的z屬性
o["x"] // =>1 表達(dá)式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á)式總會首先計算。如果計算出結(jié)果為null 或者 undefined瞳别,表達(dá)式會拋出類型錯誤異常征候。
如果運(yùn)算結(jié)果不是對象或者數(shù)組,js會將其轉(zhuǎn)換為對象洒试。
如果對象表達(dá)式后面跟隨句點(diǎn)和標(biāo)示符倍奢,則會查找由這個標(biāo)示符所指定的屬性的值,然后作為整個表達(dá)式的值返回垒棋。
如果表達(dá)式后面跟隨一對括號卒煞,則會計算方括號里面表達(dá)式值并轉(zhuǎn)換為字符串,然后查找對應(yīng)屬性的值
如果以上兩種情況叼架,命名屬性并不存在畔裕,則整個屬性訪問表達(dá)式的值就是undefined
-
.
寫法適合要訪問的屬性名是合法標(biāo)示符,并且需要知道要訪問屬性名字 -
[]
寫法適合要訪問的屬性名不是合法字符乖订,或者訪問的屬性名是需要運(yùn)算得出的扮饶。對于數(shù)組則必須使用這種寫法
調(diào)用表達(dá)式
js調(diào)用表達(dá)式,是一種調(diào)用(執(zhí)行)函數(shù)或方法的語法乍构。如下
func(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ù)
對調(diào)用表達(dá)式進(jìn)行求值時候岂丘,首先計算函數(shù)表達(dá)式,然后計算參數(shù)表達(dá)式眠饮,得到一組參數(shù)值奥帘。
如果函數(shù)表達(dá)式不是一個可以調(diào)用的對象,會拋出類型錯誤異常
如果函數(shù)表達(dá)式使用return語句返回一個值仪召,那么這個值就是整個調(diào)用表達(dá)式的值寨蹋,否則表達(dá)式的值就是undefined
對象創(chuàng)建表達(dá)式
對象創(chuàng)建表達(dá)式松蒜,顧名思義,就是創(chuàng)建一個對象已旧,并且調(diào)用一個函數(shù)秸苗,初始化新對象的屬性。
new Object()
new Point(2,6)
如果一個對象創(chuàng)建表達(dá)式不需要傳入任何參數(shù)給構(gòu)造函數(shù)评姨,那么空括號可以省略
new Object
new Date
運(yùn)算符概述
大多數(shù)運(yùn)算符都是由標(biāo)點(diǎn)符號表示的难述,如"+","="萤晴。而另外一些運(yùn)算符則是由關(guān)鍵字表示的吐句,比如delete和instanceof。
優(yōu)先級從高到低店读,虛線分割開的運(yùn)算符不同優(yōu)先級嗦枢。
運(yùn)算符 | 操作 | 結(jié)合性 | 操作數(shù)個數(shù) | 類型 |
---|---|---|---|---|
++ | 前/后增量 | 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 | 檢測操作數(shù)類型 | 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 |
--------------- | --------------- | --- | -- | --------- |
?: | 條件運(yùn)算符 | L | 3 | bool,any,any => any |
--------------- | --------------- | --- | -- | --------- |
= | 賦值運(yùn)算符 | R | 2 | lval,any => any |
*=,/=,%=,+=,-=,&= | 運(yùn)算且賦值 | R | 2 | lval,any => any |
^=,||=,<<=,>>=,>>>= | 運(yùn)算且賦值 | R | 2 | lval,any => any |
--------------- | --------------- | --- | -- | --------- |
, | 忽略第一個操作數(shù)殖演,返回第二個操作數(shù) | L | 2 | any,any => any |
左值
上表中出現(xiàn)的lval指的是左值氧秘,意思是表達(dá)式只能出現(xiàn)在賦值運(yùn)算符的左側(cè)
在js中,變量趴久、對象屬性丸相、和數(shù)組元素都是左值。
ECMAScript允許內(nèi)置函數(shù)返回左值彼棍,但自定義函數(shù)不能返回左值
操作數(shù)類型和結(jié)果類型
js運(yùn)算符通常會根據(jù)需要對操作數(shù)進(jìn)行類型轉(zhuǎn)換
*
希望操作數(shù)為數(shù)字灭忠,但是表達(dá)式"3"*"5"
卻是合法的,因?yàn)閖s會把操作數(shù)轉(zhuǎn)換為數(shù)字
有些操作符對操作數(shù)類型有一定程度依賴座硕,比如+
運(yùn)算符弛作。可以對數(shù)字進(jìn)行加法運(yùn)算华匾,也可以對字符串進(jìn)行連接映琳。
運(yùn)算符優(yōu)先級
上表中運(yùn)算符按照優(yōu)先級從高到低排序,每個虛線內(nèi)的一組運(yùn)算符具有相同優(yōu)先級蜘拉。
優(yōu)先級高的運(yùn)算符執(zhí)行總是先于優(yōu)先級低的運(yùn)算符
舉個栗子:m = x + y*z;
*
運(yùn)算符比+
運(yùn)算符優(yōu)先級高萨西,優(yōu)先計算y*z
,獲得結(jié)果再與x相加诸尽。=
賦值運(yùn)算符優(yōu)先級最低原杂,右側(cè)表達(dá)式
計算出結(jié)果后賦值給m
很多時候?yàn)榱舜a邏輯清晰,加上一些括號來重寫優(yōu)先級您机,來避免一些優(yōu)先級引起的bug或者執(zhí)行順序與設(shè)計不符
m = (x + y) * z
運(yùn)算符的結(jié)合性
上表中說明了運(yùn)算符的結(jié)合性穿肄。
- L 指從左到右結(jié)合,執(zhí)行時按照從左到右的順序進(jìn)行
- R 指從右到左結(jié)合,執(zhí)行時按照從右到左的順序進(jìn)行
舉個栗子:-
運(yùn)算符從左到右結(jié)合年局,因此w = x - y - z
等價于 w = ((x - y) - z)
運(yùn)算順序
運(yùn)算符的優(yōu)先級和結(jié)合性規(guī)定了在復(fù)雜表達(dá)式中的運(yùn)算順序,但是沒有規(guī)定子表達(dá)式的計算過程中的運(yùn)算順序
js中咸产,總是嚴(yán)格按照從左到右計算子表達(dá)式矢否。例如w=x+y*z
,首先計算w,然后計算x,y,z的值脑溢,然后y的值和z的值相承
之后僵朗,再加上x的值,最后將其結(jié)果賦值給w屑彻。給表達(dá)式加括號會改變乘法加法和賦值運(yùn)算的順序验庙,但是子表達(dá)式的計算
順序仍然是從左至右的順序
只有一種情況例外,當(dāng)任何一個表達(dá)式具有副作用而影響其他表達(dá)式時候社牲,求值順序才會有所不同粪薛。
例如,表達(dá)式中x的一個變量自增1搏恤,這個變量在z中使用违寿,那么實(shí)際上是先計算了x的值再計算z的值,這一點(diǎn)一定要注意
下面這個栗子:
a = 1;
b = (a++) + a;
如果按照前面那種不考慮副作用時的順序是 1) 計算b, 2)計算a++為c, 3)計算a熟空,4)計算c+a, 5)將c+a結(jié)果賦值給b
按照++
的影響藤巢,1) 計算b, 2)a++結(jié)果仍然為1,c=1,隨即a立即自增1, 3)計算a,a已經(jīng)是2息罗,4)計算c+a=3,5)將c+a結(jié)果賦值給b掂咒,所以b=3
切記,a增1的操作是在表達(dá)式計算中就已經(jīng)執(zhí)行了阱当,不是在整個表達(dá)式計算完成之后執(zhí)行的
算術(shù)表達(dá)式
基本算數(shù)運(yùn)算符包括+
-
*
/
%
"+"運(yùn)算符
- 對2個數(shù)字進(jìn)行加法操作
- 字符串連接操作
針對不同操作數(shù)俏扩,+運(yùn)算符行為表現(xiàn)有些不同
- 一個操作數(shù)是對象,對象會遵循對象到原始值的轉(zhuǎn)換規(guī)則轉(zhuǎn)換為原始值
- 日期對象:toString()執(zhí)行轉(zhuǎn)換
- 其他對象通過valueOf()轉(zhuǎn)換弊添,如果valueOf()不可用录淡,會通過toString()方法轉(zhuǎn)換
- 在進(jìn)行對象到原始值的轉(zhuǎn)換后,如果其中一個操作數(shù)是字符串油坝,另一個操作數(shù)也會轉(zhuǎn)換成字符串嫉戚,然后連接
- 否則,兩個操作數(shù)都轉(zhuǎn)換成數(shù)字或者NaN澈圈,然后進(jìn)行加法操作
下面是一些栗子:
1 + 2 // =>3
"1" + 2 // => "12"
"12" + "3" // => "123"
1 + {} // "1[object object]"彬檀,對象轉(zhuǎn)換為字符串
true + true // 2 ,bool轉(zhuǎn)換為數(shù)字做加法
2 + null // =>2,null轉(zhuǎn)換為0
2 + undefined // => NaN, undefined轉(zhuǎn)換為NaN后做加法
最后瞬女,還需要考慮窍帝,加法的結(jié)合性對運(yùn)算順序的影響
1 + 2 + "hello" // "3hello"
1 + (2 + "hello") // "12hello"
一元算術(shù)運(yùn)算符
一元運(yùn)算符作用于一個單獨(dú)操作數(shù),產(chǎn)生一個新值
js中一元運(yùn)算符優(yōu)先級很高诽偷,并且都是右結(jié)合
+
/-
坤学,既是一元運(yùn)算符疯坤,也是二元運(yùn)算符
- 一元加法(
+
)
操作數(shù)轉(zhuǎn)換為數(shù)字(或者NaN),并且返回這個轉(zhuǎn)換后的數(shù)字深浮。如果已經(jīng)是數(shù)字压怠,直接返回
- 一元減法(
-
)
操作數(shù)轉(zhuǎn)換為數(shù)字(或者NaN),并且返回這個轉(zhuǎn)換后的數(shù)字飞苇,然后改變運(yùn)算結(jié)果符號
- 遞增(
++
)
前增量
++a
菌瘫,先進(jìn)行增量運(yùn)算并且返回運(yùn)算結(jié)果
后增量a++
,先進(jìn)行增量計算布卡,返回未做增量運(yùn)算的值
var i=1, j=i++; // i=2,j=1
var i=1, j=++i; // i=2,j=2
- 遞減(`--`)
> 前減量 `--a`雨让,先進(jìn)行減量運(yùn)算并且返回運(yùn)算結(jié)果
> 后減量 `a--`,先進(jìn)行減量計算羽利,返回未做減量運(yùn)算的值
> ```
var i=1, j=i--; // i=0,j=1
var i=1, j=--i; // i=0,j=0
位運(yùn)算符
-
&
按位與
0x1234 & 0x00ff = 0x0034
-
|
按位或
0x1234 | 0x00ff = 0x12ff
-
^
按位異或
0xff00 ^ 0xf0f0 = 0x0ff0
-
~
按位非
~0x0f = 0xfffffff0
-
<<
左移
7 << 2 = 28
,左移一位相當(dāng)于第一個操作數(shù)乘以2
移動位數(shù) 0~31
-
>>
帶符號右移
帶符號右移時候填補(bǔ)在左邊的位由原來的數(shù)的符號決定宫患,以便保持和原操作數(shù)一致
移動位數(shù) 0~31
7 >> 1 = 3
-7 >> 1 = -4
-
>>>
無符號右移
無符號右移時候填補(bǔ)在左邊的位直接填補(bǔ)0,與原操作數(shù)無關(guān)
移動位數(shù) 0~31
-1 >> 4 = 1
-1 >>> 4 = 0x0fffffff
關(guān)系表達(dá)式
主要包括相等和不相等運(yùn)算符这弧、比較運(yùn)算符、in虚汛、instanceof
相等和不相等運(yùn)算符
js定義了4個符號==
,===
,!=
,!==
-
==
:相等 -
===
: 恒等 -
!=
: 不相等 -
!==
: 不恒等
嚴(yán)格相等運(yùn)算符===
首先計算其操作數(shù)的值匾浪,然后比較這兩個值,沒有類型轉(zhuǎn)換
- 如果兩個值類型不相同卷哩,則它們不相等
- 如果兩個值都是null或者都是undefined蛋辈,則它們不相等
- 如果兩個值都是布爾值true或者false,将谊,則它們相等
- 如果其中一個值是NaN冷溶,或者2個值都是NaN,則它們不相等尊浓。NaN和其他任何值都是不相等的逞频,包括自身。通過X!==X來判斷x是否為NaN栋齿,只有x為NaN時候苗胀,表達(dá)式才為true
- 如果兩個值為數(shù)字且數(shù)值相等,則他們相等瓦堵。如果一個值為0基协,另一個為-0,同樣相等
- 如果兩個值為字符串菇用,且所含對應(yīng)位上16位數(shù)完全相等澜驮,則他們相當(dāng)。如果它們長度或內(nèi)容不同惋鸥,則它們不相等杂穷。
- 兩個字符串可能含義完全一樣且顯示字符一樣鹅龄,但具有不同編碼的16位值。js不會對Unicode進(jìn)行標(biāo)準(zhǔn)化轉(zhuǎn)換亭畜,像這樣字符串通過"==="和"=="運(yùn)算符比較結(jié)果也是不相等
- 如果兩個引用值指向同一個對象扮休、數(shù)組或者函數(shù),則相等拴鸵。如果指向不同對象玷坠,則它們不相等,盡管兩個對象完全一樣的屬性劲藐。
相等運(yùn)算符==
和恒等運(yùn)算符相似八堡,但相等運(yùn)算符并不嚴(yán)格。如果兩個操作數(shù)不是同一類型聘芜,那么相等的運(yùn)算符會進(jìn)行一些類型轉(zhuǎn)換兄渺,然后進(jìn)行比較
- 如果兩個操作數(shù)的類型相同,則和上文所屬的嚴(yán)格相等的比較規(guī)則一樣汰现。如果嚴(yán)格相等挂谍,則比較結(jié)果相等,如果不嚴(yán)格相等瞎饲,則它們不相等
- 如果兩個操作數(shù)類型不同口叙,
==
相等操作符也可能認(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,在進(jìn)行比較
- 如果一個值是對象苇倡,另一個值是數(shù)字或字符串富纸,則會使用之前提到的對象到數(shù)字或字符串的轉(zhuǎn)換規(guī)則將對象轉(zhuǎn)換為原始值,然后進(jìn)行比較旨椒。
- 其他的類型之間的比較均不相等
舉個栗子:"1" == true
這個表達(dá)式結(jié)果是true晓褪,表明不同類型之間的值比較結(jié)果相等。布爾值首先轉(zhuǎn)換為數(shù)字1综慎,然后字符串1也轉(zhuǎn)換成數(shù)字1涣仿,因?yàn)閮蓚€數(shù)字相等,所以結(jié)果為true
比較運(yùn)算符
比較運(yùn)算符有4個
-
<
小于 -
>
大于 -
<=
小于等于 -
>=
大于等于
比較運(yùn)算符的操作數(shù)可以是任何類型,然后只有字符串和數(shù)字才能真正的執(zhí)行比較操作好港,不是這兩種類型的都將進(jìn)行類型轉(zhuǎn)換愉镰。
類型轉(zhuǎn)換規(guī)則:
- 如果操作數(shù)為對象,這個對象將按照對象到原始值的轉(zhuǎn)換(具體可以看上篇)
- 在對象轉(zhuǎn)換到原始值后钧汹,如果兩個操作數(shù)都是字符串丈探,那么將按照字母表順序進(jìn)行比較(字母表指的unicode 16位字符的索引順序)
- 對象轉(zhuǎn)換為原始值后,如果一個操作數(shù)不是字符串拔莱,那么兩個操作數(shù)轉(zhuǎn)換為數(shù)字之后進(jìn)行比較碗降。
- 0和-0是相等的
- Infinity比其他任何數(shù)字都大(除了自身)
- -Infinity比其他數(shù)字都小(除了自身)
- 如果一個操作數(shù)轉(zhuǎn)換成數(shù)字之后是NaN,那么比較操作符總是返回false
在上面規(guī)則中塘秦,字符串比較需要注意:
- 字符串比較是區(qū)分大小寫的讼渊,所有的大寫ascii字符都是小于小寫的ascii字符
- 對于數(shù)字和字符串比較,只有兩個操作數(shù)都是字符串時尊剔,才會進(jìn)行字符串比較
in
運(yùn)算符
in
運(yùn)算符的左邊總是希望是一個字符串爪幻,右邊操作數(shù)總是希望是一個對象,如果右邊對象擁有左操作值的屬性名须误,會返回true
對象挨稿,會傾向查找屬性名
var point = { x:1, y:1};
"x" in point // => true, 對象擁有名為“x”的屬性
"z" in point // => false, 對象不存在名為"z"的屬性
"toString" in point // => true,對象繼承了默認(rèn)的toString()方法
數(shù)組霹期,會傾向查找索引
var data = [1,2,3]
"0" in data // true叶组,數(shù)組包含索引0的元素
1 in data // true,數(shù)組包含索引1的元素
3 in data // false 數(shù)組不包含索引3的元素
instanceof
運(yùn)算符
instanceof
運(yùn)算符希望左操作數(shù)是一個對象历造,右操作數(shù)標(biāo)識對象的類,如果左側(cè)的對象是右側(cè)類的實(shí)例船庇,則返回true吭产,否則返回false
var d = new Date();
d instanceof Date; // true,d是由Date()創(chuàng)建的
d instanceof Object; // true,所有對象都是Object實(shí)例
d instanceof Number; // false, d不是Number的實(shí)例
邏輯表達(dá)式
邏輯運(yùn)算符是進(jìn)行布爾運(yùn)算使用的鸭轮,主要有
-
&&
邏輯與 -
||
邏輯或 -
!
邏輯非
邏輯與(&&)
當(dāng)操作數(shù)都是布爾值時臣淤,&&
對兩個值進(jìn)行布爾與操作,第一個與第二個操作數(shù)都是true時窃爷,才返回true邑蒋,其中一個是false,就會返回false
當(dāng)操作數(shù)不都是布爾值時按厘,&&
不一定會返回布爾值医吊。
- 邏輯與運(yùn)算符,首先計算左側(cè)的值逮京,如果計算結(jié)果是假植卿堂,則整個表達(dá)式都是假植,因此會簡單的返回左側(cè)操作數(shù)的值
- 如果左側(cè)值是真值,那么整個表達(dá)式結(jié)果依賴于右側(cè)的值草描,因此览绿,
&&
運(yùn)算符符會計算右側(cè)操作數(shù)的值,并且將其返回作為整個表達(dá)式的計算結(jié)果
var o ={ x:1 };
var p = null;
o && o.x; // =>1 穗慕,o對象是真值饿敲,返回o.x
p && p.x; // => null ,p是假值逛绵,將其返回怀各,不會計算p.x
上面那種行為,被稱為 短路,這一特性非常有用暑脆,可以選擇性執(zhí)行代碼渠啤。 例如:
if ( a == b ) stop();
等價于 ( a == b ) && stop();
邏輯或(||)
當(dāng)操作數(shù)都是布爾值時,||
對兩個操作數(shù)作布爾或運(yùn)算添吗,兩個操作數(shù)有一個為真沥曹,返回true,兩個操作數(shù)都是假碟联,才會返回false
當(dāng)操作數(shù)不都是布爾值妓美,||
不一定返回布爾值
- 邏輯或運(yùn)算符,首先計算左側(cè)的值鲤孵,如果計算結(jié)果是真值壶栋,則整個表達(dá)式都是真值,因此會返回這個真值
- 否則再計算第二個操作數(shù)的值普监,再返回這個表達(dá)式的計算結(jié)果
||
同樣是非常有用贵试,比如從一組備選表達(dá)式中選出第一個真值表達(dá)式。這種做法經(jīng)常在函數(shù)體內(nèi)凯正,給參數(shù)提供默認(rèn)值
var max = max_width || preference.max_width || 500;
邏輯非(!)
!
運(yùn)算符是一元運(yùn)算符毙玻,放在一個單獨(dú)的操作數(shù)前,對操作數(shù)布爾值進(jìn)行求反
!
運(yùn)算符首先將操作數(shù)轉(zhuǎn)換為布爾值廊散,再進(jìn)行求反桑滩,最終只會返回true或者false
作為一元運(yùn)算符,優(yōu)先級非常高允睹,并且和操作數(shù)密切綁定运准。
德摩根公式:
!(p && q) === !p || !q
!(p || q) === !p && !q
賦值表達(dá)式
js 使用=
運(yùn)算符給變量或者屬性進(jìn)行賦值
i = 0;
0.x = 1;
除了常規(guī)的賦值運(yùn)算符,還有一些帶賦值操作的運(yùn)算符+=
,-=
,*=
,&=
等等
只有+=
可以用于數(shù)字或字符串連接缭受,其他都偏向于數(shù)值操作
a = 10;
b = '1';
a += 10; // => 10 + 10 =20
b += 10; // => '1'+10 = "110"
a -= 10; // => 20 - 10 = 10
b -= 10; // => 110 - 10 = 10
表達(dá)式計算
js可以通過eval()
來動態(tài)判斷源代碼中的字符串胁澳,并且執(zhí)行
eval()
只有一個參數(shù),如果傳入的參數(shù)不是字符串贯涎,直接返回這個參數(shù)听哭。如果參數(shù)是字符串,則會把字符串當(dāng)成代碼進(jìn)行編譯。
如果編譯失敗陆盘,則返回一個語法錯誤異常普筹。如果編譯成功,則會執(zhí)行這段代碼隘马,并且返回字符串最后一個表達(dá)式或者語句的值太防。
如果最后一個表達(dá)式或語句沒有值,則最終返回undefined
eval()
使用來調(diào)用它的變量作用域環(huán)境酸员,也就是說查找變量會和局部作用域代碼完全一樣蜒车。
如果將eval()
重命名為其他方式來調(diào)用,則使用全局對象作為上下文作用域幔嗦,并且無法讀酿愧、寫、定義局部變量
var geval = eval; // geval 是調(diào)用全局eval
var x = "global";
var y = "global";
function f(){
var x = "local"; // 定義局部變量 x邀泉,局部作用域x = “l(fā)ocal”
eval("x+='changed';"); // 直接eval更改局部變量x的值
return x; // 返回更改后的x值
}
function g(){
var y = "local"; // 定義局部變量 y嬉挡,局部作用域y = “l(fā)ocal”
geval("y+='changed';"); // 間接調(diào)用改變?nèi)肿兞康闹? return y; // 返回為更改的局部變量
}
console.log(f(),x); // 更改來局部變量,輸出"localchanged global"
console.log(g(),y); // 更改全局變量汇恤,輸出“l(fā)ocal globalchanged”
其他運(yùn)算符
條件運(yùn)算符(?:)
條件運(yùn)算符是唯一一個三元運(yùn)算符
(---1---) ? (---2---) : (---3---)
第一個操作數(shù)當(dāng)成布爾值庞钢,如果是真值,那么計算第二個操作數(shù)因谎,并返回結(jié)果基括。否則如果第一個操作數(shù)是假植,那么計算第三個數(shù)财岔,返回計算結(jié)果
x > 0 ? x : -x // 求x的絕對值
typeof運(yùn)算符
x | typeof x |
---|---|
undefined | "undefined" |
null | "object" |
true or false | "boolean" |
任意數(shù)字或NaN | "number" |
任意字符串 | "string" |
任意函數(shù) | "function" |
任意內(nèi)置對象 | "object" |
任意宿主對象 | 由編譯器實(shí)現(xiàn)的字符串风皿,但不是以上出現(xiàn)的字符串 |
這是一個一元運(yùn)算符,返回表示操作數(shù)類型的一個字符串
x | typeof x |
---|---|
undefined | "undefined" |
null | "object" |
true or false | "boolean" |
任意數(shù)字或NaN | "number" |
任意字符串 | "string" |
任意函數(shù) | "function" |
任意內(nèi)置對象 | "object" |
任意宿主對象 | 由編譯器實(shí)現(xiàn)的字符串匠璧,但不是以上出現(xiàn)的字符串 |
delete運(yùn)算符
delete運(yùn)算符揪阶,用來刪除對象屬性或者數(shù)組元素
var o = { x:1, y:2};
delete o.x; // 刪除一個屬性
"x" in o; // false,o對象中不存在屬性x
var a = [1,23,4];
delete a[2]; //刪除第三個元素
2 in a ; // false, 索引2的元素在數(shù)組中已經(jīng)不存在
delete刪除成功會返回true患朱。然后不是所有屬性都可刪除的
- 一些內(nèi)置核心和客戶端屬性是不能刪除的
- 使用var語句生聲明的變量不能刪除
- 通過function定義的函數(shù)和函數(shù)參數(shù)不能刪除。
var 0 = { x:1, y:2};
delete o.x; // true, 刪除對象屬性成功
typeof o.x; // undefined 炊苫, 屬性不存在
delete o.x; // true, 刪除不存在的屬性裁厅,返回true
delete o; // false ,不能刪除var聲明變量
delete 1; // true, 參數(shù)不是一個左值侨艾,返回true
this.x = 1; // 定義全局對象的一個屬性
delete x; // 試圖刪除全局變量的屬性执虹,非嚴(yán)格模式下,返回true
x; // 運(yùn)行時錯誤唠梨,沒有定義x
void 運(yùn)算符
void 是一元運(yùn)算符袋励,操作數(shù)照常計算,但是忽略計算結(jié)果并且返回undefined
這個操作符經(jīng)常用作客戶端URL-javascript:URL
,通過使用void則讓瀏覽器不必顯示這個表達(dá)式計算結(jié)果
<a href="javascript:void window.open();">打開一個新窗口</a>
逗號運(yùn)算符
逗號運(yùn)算符,首先計算左操作數(shù)茬故,然后計算右操作數(shù)盖灸,最后返回右操作數(shù)的值。
總會計算左側(cè)的表達(dá)式磺芭,但計算結(jié)果忽略掉赁炎,也就是說,只有左側(cè)表達(dá)式有副作用時钾腺,徙垫,才會使用逗號表達(dá)式讓代碼更通順。
經(jīng)常在for循環(huán)中使用
for(var i=0,j=10;i<j;i++,j--){
console.log(i+j);
}