JavaScript 從入門(mén)到放棄 - 3 - 表達(dá)式和運(yùn)算符

表達(dá)式和運(yùn)算符

  • 程序中最簡(jiǎn)單的表達(dá)式就是,程序中的常量
  • 變量名也是一種簡(jiǎn)單的表達(dá)式
  • 復(fù)雜的表達(dá)式是由簡(jiǎn)單的表達(dá)式組成的
  • 函數(shù)調(diào)用表達(dá)式是由函數(shù)對(duì)象的表達(dá)式和0個(gè)或多個(gè)參數(shù)表達(dá)式構(gòu)成
  • 可以使用運(yùn)算符來(lái)將簡(jiǎn)單的表達(dá)式來(lái)組合成復(fù)雜的表達(dá)式

原始表達(dá)式

“原始表達(dá)式”,說(shuō)簡(jiǎn)單點(diǎn)就是最簡(jiǎn)單的表達(dá)式,并且不再包含其他表達(dá)式

js中原始表達(dá)式有以下:

  • 常量
  • 直接量
  • 關(guān)鍵字
  • 變量

栗子:

//直接量          
1.23 // 數(shù)字直接量
"hello" // 字符串直接量
/pattern/ // 正則表達(dá)式直接
//保留字   
true
false
null // 返回空
this // 返回“當(dāng)前對(duì)象”
//變量         
i // 返回i的值
sum // 返回sum的值
undefined // undefined是全局變量,和null不同,不是一個(gè)關(guān)鍵字

對(duì)象和數(shù)組的初始化表達(dá)式

對(duì)象和數(shù)組的初始化表達(dá)式實(shí)際上是一個(gè)新創(chuàng)建的對(duì)象和數(shù)組,并不是原始表達(dá)式

數(shù)組初始化表達(dá)式

栗子:

  • [] //空數(shù)組
  • [1+2,3+4] // 2個(gè)元素?cái)?shù)組 [3,7]
  • var matrix = [[1,2],[3,4]] // 數(shù)組可嵌套

js對(duì)數(shù)組初始化表達(dá)式進(jìn)行求值時(shí)候,數(shù)組表達(dá)式中的所有元素表達(dá)式也會(huì)各自計(jì)算一次

數(shù)組直接量的元素表達(dá)式在逗號(hào)之間元素可以省略,空位默認(rèn)填充undefined。
var array = [1,,3] // 數(shù)組包含3個(gè)元素。[1,undefined,3]

但是列表結(jié)尾處可以留下單個(gè)逗號(hào),這時(shí)不會(huì)創(chuàng)建新的undefined元素

對(duì)象初始化表達(dá)式

對(duì)象初始化表達(dá)式與數(shù)組初始化表達(dá)式非常接近,將[]替換成{},每個(gè)子表達(dá)式都包含一個(gè)屬性名和冒號(hào)為前綴

栗子

var p = { x:2, y:3 }; // 帶2個(gè)屬性的對(duì)象p
var q = {}; // 空對(duì)象
q.x = 2; q.y =3; // q的屬性成員與p一致

對(duì)象直接量也是允許嵌套的

var rect = {
upLeft: { x:2, y:3},
bottomRight: { x:4, y:1}
};


js求對(duì)象初始化表達(dá)式時(shí)候,對(duì)象元素表達(dá)式也會(huì)各自都計(jì)算一次,并且元素表達(dá)式不必包含常數(shù)值,可以是
任意的js表達(dá)式。

對(duì)象直接量中屬性的名字可以是字符串而不是標(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á)式定義一個(gè)js函數(shù),表達(dá)式的值是這個(gè)新定義的函數(shù)。如下

var square = function (x){
  return x * x;
};

屬性訪問(wèn)表達(dá)式

屬性訪問(wèn)表達(dá)式得到一個(gè)對(duì)象屬性或一個(gè)數(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á)式總會(huì)首先計(jì)算。如果計(jì)算出結(jié)果為null 或者 undefined,表達(dá)式會(huì)拋出類(lèi)型錯(cuò)誤異常。
如果運(yùn)算結(jié)果不是對(duì)象或者數(shù)組,js會(huì)將其轉(zhuǎn)換為對(duì)象。

如果對(duì)象表達(dá)式后面跟隨句點(diǎn)和標(biāo)示符,則會(huì)查找由這個(gè)標(biāo)示符所指定的屬性的值,然后作為整個(gè)表達(dá)式的值返回。

如果表達(dá)式后面跟隨一對(duì)括號(hào),則會(huì)計(jì)算方括號(hào)里面表達(dá)式值并轉(zhuǎn)換為字符串,然后查找對(duì)應(yīng)屬性的值

如果以上兩種情況,命名屬性并不存在,則整個(gè)屬性訪問(wèn)表達(dá)式的值就是undefined

  • .寫(xiě)法適合要訪問(wèn)的屬性名是合法標(biāo)示符,并且需要知道要訪問(wèn)屬性名字
  • [] 寫(xiě)法適合要訪問(wèn)的屬性名不是合法字符,或者訪問(wèn)的屬性名是需要運(yùn)算得出的。對(duì)于數(shù)組則必須使用這種寫(xiě)法

調(diào)用表達(dá)式

js調(diào)用表達(dá)式,是一種調(diào)用(執(zhí)行)函數(shù)或方法的語(yǔ)法。如下

func(0) // f是一個(gè)函數(shù)表達(dá)式,0是一個(gè)參數(shù)表達(dá)式
Math.max(x,y,z) // Math.max是一個(gè)函數(shù),x,y,z是參數(shù)
a.sort() // a.sort是一個(gè)函數(shù)。沒(méi)有參數(shù)

對(duì)調(diào)用表達(dá)式進(jìn)行求值時(shí)候,首先計(jì)算函數(shù)表達(dá)式,然后計(jì)算參數(shù)表達(dá)式,得到一組參數(shù)值。

如果函數(shù)表達(dá)式不是一個(gè)可以調(diào)用的對(duì)象,會(huì)拋出類(lèi)型錯(cuò)誤異常

如果函數(shù)表達(dá)式使用return語(yǔ)句返回一個(gè)值,那么這個(gè)值就是整個(gè)調(diào)用表達(dá)式的值,否則表達(dá)式的值就是undefined

對(duì)象創(chuàng)建表達(dá)式

對(duì)象創(chuàng)建表達(dá)式,顧名思義,就是創(chuàng)建一個(gè)對(duì)象,并且調(diào)用一個(gè)函數(shù),初始化新對(duì)象的屬性。

new Object()
new Point(2,6)

如果一個(gè)對(duì)象創(chuàng)建表達(dá)式不需要傳入任何參數(shù)給構(gòu)造函數(shù),那么空括號(hào)可以省略

new Object
new Date

運(yùn)算符概述

大多數(shù)運(yùn)算符都是由標(biāo)點(diǎn)符號(hào)表示的,如"+","="。而另外一些運(yùn)算符則是由關(guān)鍵字表示的,比如delete和instanceof。

優(yōu)先級(jí)從高到低,虛線分割開(kāi)的運(yùn)算符不同優(yōu)先級(jí)。

運(yùn)算符 操作 結(jié)合性 操作數(shù)個(gè)數(shù) 類(lèi)型
++ 前/后增量 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 檢測(cè)操作數(shù)類(lèi)型 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
>> 無(wú)符號(hào)右移位 L 2 int,int => int
>>> 有符號(hào)右移位 L 2 int,int => int
--------------- --------------- --- -- ---------
<,<=,>,>= 比較數(shù)字順序 L 2 num,num => bool
<,<=,>,>= 比較在字母表順序 L 2 str,str => bool
instanceof 測(cè)試對(duì)象類(lèi) L 2 obj,func => bool
in 測(cè)試屬性是否存在 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
--------------- --------------- --- -- ---------
, 忽略第一個(gè)操作數(shù),返回第二個(gè)操作數(shù) L 2 any,any => any

左值

上表中出現(xiàn)的lval指的是左值,意思是表達(dá)式只能出現(xiàn)在賦值運(yùn)算符的左側(cè)

在js中,變量、對(duì)象屬性、和數(shù)組元素都是左值。

ECMAScript允許內(nèi)置函數(shù)返回左值,但自定義函數(shù)不能返回左值

操作數(shù)類(lèi)型和結(jié)果類(lèi)型

js運(yùn)算符通常會(huì)根據(jù)需要對(duì)操作數(shù)進(jìn)行類(lèi)型轉(zhuǎn)換

*希望操作數(shù)為數(shù)字,但是表達(dá)式"3"*"5"卻是合法的,因?yàn)閖s會(huì)把操作數(shù)轉(zhuǎn)換為數(shù)字

有些操作符對(duì)操作數(shù)類(lèi)型有一定程度依賴(lài),比如運(yùn)算符。可以對(duì)數(shù)字進(jìn)行加法運(yùn)算,也可以對(duì)字符串進(jìn)行連接。

運(yùn)算符優(yōu)先級(jí)

上表中運(yùn)算符按照優(yōu)先級(jí)從高到低排序,每個(gè)虛線內(nèi)的一組運(yùn)算符具有相同優(yōu)先級(jí)。

優(yōu)先級(jí)高的運(yùn)算符執(zhí)行總是先于優(yōu)先級(jí)低的運(yùn)算符
舉個(gè)栗子:m = x + y*z;
*運(yùn)算符比運(yùn)算符優(yōu)先級(jí)高,優(yōu)先計(jì)算y*z,獲得結(jié)果再與x相加。=賦值運(yùn)算符優(yōu)先級(jí)最低,右側(cè)表達(dá)式
計(jì)算出結(jié)果后賦值給m

很多時(shí)候?yàn)榱舜a邏輯清晰,加上一些括號(hào)來(lái)重寫(xiě)優(yōu)先級(jí),來(lái)避免一些優(yōu)先級(jí)引起的bug或者執(zhí)行順序與設(shè)計(jì)不符
m = (x + y) * z

運(yùn)算符的結(jié)合性

上表中說(shuō)明了運(yùn)算符的結(jié)合性。

  • L 指從左到右結(jié)合,執(zhí)行時(shí)按照從左到右的順序進(jìn)行
  • R 指從右到左結(jié)合,執(zhí)行時(shí)按照從右到左的順序進(jìn)行

舉個(gè)栗子:-運(yùn)算符從左到右結(jié)合,因此w = x - y - z 等價(jià)于 w = ((x - y) - z)

運(yùn)算順序

運(yùn)算符的優(yōu)先級(jí)和結(jié)合性規(guī)定了在復(fù)雜表達(dá)式中的運(yùn)算順序,但是沒(méi)有規(guī)定子表達(dá)式的計(jì)算過(guò)程中的運(yùn)算順序

js中,總是嚴(yán)格按照從左到右計(jì)算子表達(dá)式。例如w=x+y*z,首先計(jì)算w,然后計(jì)算x,y,z的值,然后y的值和z的值相承
之后,再加上x(chóng)的值,最后將其結(jié)果賦值給w。給表達(dá)式加括號(hào)會(huì)改變乘法加法和賦值運(yùn)算的順序,但是子表達(dá)式的計(jì)算
順序仍然是從左至右的順序

只有一種情況例外,當(dāng)任何一個(gè)表達(dá)式具有副作用而影響其他表達(dá)式時(shí)候,求值順序才會(huì)有所不同。
例如,表達(dá)式中x的一個(gè)變量自增1,這個(gè)變量在z中使用,那么實(shí)際上是先計(jì)算了x的值再計(jì)算z的值,這一點(diǎn)一定要注意

下面這個(gè)栗子:

a = 1;
b = (a++) + a;

如果按照前面那種不考慮副作用時(shí)的順序是 1) 計(jì)算b, 2)計(jì)算a++為c, 3)計(jì)算a,4)計(jì)算c+a, 5)將c+a結(jié)果賦值給b

按照++的影響,1) 計(jì)算b, 2)a++結(jié)果仍然為1,c=1,隨即a立即自增1, 3)計(jì)算a,a已經(jīng)是2,4)計(jì)算c+a=3,5)將c+a結(jié)果賦值給b,所以b=3

切記,a增1的操作是在表達(dá)式計(jì)算中就已經(jīng)執(zhí)行了,不是在整個(gè)表達(dá)式計(jì)算完成之后執(zhí)行的

算術(shù)表達(dá)式

基本算數(shù)運(yùn)算符包括+ - * / %

"+"運(yùn)算符

  • 對(duì)2個(gè)數(shù)字進(jìn)行加法操作
  • 字符串連接操作

針對(duì)不同操作數(shù),+運(yùn)算符行為表現(xiàn)有些不同

  • 一個(gè)操作數(shù)是對(duì)象,對(duì)象會(huì)遵循對(duì)象到原始值的轉(zhuǎn)換規(guī)則轉(zhuǎn)換為原始值
  • 日期對(duì)象:toString()執(zhí)行轉(zhuǎn)換
  • 其他對(duì)象通過(guò)valueOf()轉(zhuǎn)換,如果valueOf()不可用,會(huì)通過(guò)toString()方法轉(zhuǎn)換
  • 在進(jìn)行對(duì)象到原始值的轉(zhuǎn)換后,如果其中一個(gè)操作數(shù)是字符串,另一個(gè)操作數(shù)也會(huì)轉(zhuǎn)換成字符串,然后連接
  • 否則,兩個(gè)操作數(shù)都轉(zhuǎn)換成數(shù)字或者NaN,然后進(jìn)行加法操作

下面是一些栗子:

1 + 2 // =>3
"1" + 2 // => "12"
"12" + "3" // => "123"
1 + {} // "1[object object]",對(duì)象轉(zhuǎn)換為字符串
true + true // 2 ,bool轉(zhuǎn)換為數(shù)字做加法

2 + null // =>2,null轉(zhuǎn)換為0
2 + undefined // => NaN, undefined轉(zhuǎn)換為NaN后做加法

最后,還需要考慮,加法的結(jié)合性對(duì)運(yùn)算順序的影響

1 + 2 + "hello" // "3hello"
1 + (2 + "hello") // "12hello"

一元算術(shù)運(yùn)算符

一元運(yùn)算符作用于一個(gè)單獨(dú)操作數(shù),產(chǎn)生一個(gè)新值

js中一元運(yùn)算符優(yōu)先級(jí)很高,并且都是右結(jié)合

+/-,既是一元運(yùn)算符,也是二元運(yùn)算符

  • 一元加法(+)

操作數(shù)轉(zhuǎn)換為數(shù)字(或者NaN),并且返回這個(gè)轉(zhuǎn)換后的數(shù)字。如果已經(jīng)是數(shù)字,直接返回

  • 一元減法(-)

操作數(shù)轉(zhuǎn)換為數(shù)字(或者NaN),并且返回這個(gè)轉(zhuǎn)換后的數(shù)字,然后改變運(yùn)算結(jié)果符號(hào)

  • 遞增(++)

前增量 ++a,先進(jìn)行增量運(yùn)算并且返回運(yùn)算結(jié)果
后增量 a++,先進(jìn)行增量計(jì)算,返回未做增量運(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)行減量計(jì)算,返回未做減量運(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)于第一個(gè)操作數(shù)乘以2
移動(dòng)位數(shù) 0~31

  • >> 帶符號(hào)右移

帶符號(hào)右移時(shí)候填補(bǔ)在左邊的位由原來(lái)的數(shù)的符號(hào)決定,以便保持和原操作數(shù)一致
移動(dòng)位數(shù) 0~31
7 >> 1 = 3
-7 >> 1 = -4

  • >>> 無(wú)符號(hào)右移

無(wú)符號(hào)右移時(shí)候填補(bǔ)在左邊的位直接填補(bǔ)0,與原操作數(shù)無(wú)關(guān)
移動(dòng)位數(shù) 0~31
-1 >> 4 = 1
-1 >>> 4 = 0x0fffffff

關(guān)系表達(dá)式

主要包括相等和不相等運(yùn)算符、比較運(yùn)算符、in、instanceof

相等和不相等運(yùn)算符

js定義了4個(gè)符號(hào)==,===,!=,!==

  • ==:相等
  • ===: 恒等
  • !=: 不相等
  • !==: 不恒等

嚴(yán)格相等運(yùn)算符===首先計(jì)算其操作數(shù)的值,然后比較這兩個(gè)值,沒(méi)有類(lèi)型轉(zhuǎn)換

  • 如果兩個(gè)值類(lèi)型不相同,則它們不相等
  • 如果兩個(gè)值都是null或者都是undefined,則它們不相等
  • 如果兩個(gè)值都是布爾值true或者false,,則它們相等
  • 如果其中一個(gè)值是NaN,或者2個(gè)值都是NaN,則它們不相等。NaN和其他任何值都是不相等的,包括自身。通過(guò)X!==X來(lái)判斷x是否為NaN,只有x為NaN時(shí)候,表達(dá)式才為true
  • 如果兩個(gè)值為數(shù)字且數(shù)值相等,則他們相等。如果一個(gè)值為0,另一個(gè)為-0,同樣相等
  • 如果兩個(gè)值為字符串,且所含對(duì)應(yīng)位上16位數(shù)完全相等,則他們相當(dāng)。如果它們長(zhǎng)度或內(nèi)容不同,則它們不相等。
  • 兩個(gè)字符串可能含義完全一樣且顯示字符一樣,但具有不同編碼的16位值。js不會(huì)對(duì)Unicode進(jìn)行標(biāo)準(zhǔn)化轉(zhuǎn)換,像這樣字符串通過(guò)"==="和"=="運(yùn)算符比較結(jié)果也是不相等
  • 如果兩個(gè)引用值指向同一個(gè)對(duì)象、數(shù)組或者函數(shù),則相等。如果指向不同對(duì)象,則它們不相等,盡管兩個(gè)對(duì)象完全一樣的屬性。

相等運(yùn)算符==和恒等運(yùn)算符相似,但相等運(yùn)算符并不嚴(yán)格。如果兩個(gè)操作數(shù)不是同一類(lèi)型,那么相等的運(yùn)算符會(huì)進(jìn)行一些類(lèi)型轉(zhuǎn)換,然后進(jìn)行比較

  • 如果兩個(gè)操作數(shù)的類(lèi)型相同,則和上文所屬的嚴(yán)格相等的比較規(guī)則一樣。如果嚴(yán)格相等,則比較結(jié)果相等,如果不嚴(yán)格相等,則它們不相等
  • 如果兩個(gè)操作數(shù)類(lèi)型不同,==相等操作符也可能認(rèn)為他們相等。檢測(cè)相等會(huì)遵守以下規(guī)則和類(lèi)型轉(zhuǎn)換
  • 如果一個(gè)值是null,另一個(gè)是undefined,則他們相等
  • 如果一個(gè)值是數(shù)字,另一個(gè)是字符串,先將字符串轉(zhuǎn)換成數(shù)字,然后使用轉(zhuǎn)換后的值,進(jìn)行比較
  • 如果其中一個(gè)值是true,則將其轉(zhuǎn)換為1再進(jìn)行比較。如果其中一個(gè)值是false,則將其轉(zhuǎn)化為0,在進(jìn)行比較
  • 如果一個(gè)值是對(duì)象,另一個(gè)值是數(shù)字或字符串,則會(huì)使用之前提到的對(duì)象到數(shù)字或字符串的轉(zhuǎn)換規(guī)則將對(duì)象轉(zhuǎn)換為原始值,然后進(jìn)行比較。
  • 其他的類(lèi)型之間的比較均不相等

舉個(gè)栗子:"1" == true
這個(gè)表達(dá)式結(jié)果是true,表明不同類(lèi)型之間的值比較結(jié)果相等。布爾值首先轉(zhuǎn)換為數(shù)字1,然后字符串1也轉(zhuǎn)換成數(shù)字1,因?yàn)閮蓚€(gè)數(shù)字相等,所以結(jié)果為true

比較運(yùn)算符

比較運(yùn)算符有4個(gè)

  • < 小于
  • > 大于
  • <= 小于等于
  • >= 大于等于

比較運(yùn)算符的操作數(shù)可以是任何類(lèi)型,然后只有字符串和數(shù)字才能真正的執(zhí)行比較操作,不是這兩種類(lèi)型的都將進(jìn)行類(lèi)型轉(zhuǎn)換。
類(lèi)型轉(zhuǎn)換規(guī)則:

  • 如果操作數(shù)為對(duì)象,這個(gè)對(duì)象將按照對(duì)象到原始值的轉(zhuǎn)換(具體可以看上篇)
  • 在對(duì)象轉(zhuǎn)換到原始值后,如果兩個(gè)操作數(shù)都是字符串,那么將按照字母表順序進(jìn)行比較(字母表指的unicode 16位字符的索引順序)
  • 對(duì)象轉(zhuǎn)換為原始值后,如果一個(gè)操作數(shù)不是字符串,那么兩個(gè)操作數(shù)轉(zhuǎn)換為數(shù)字之后進(jìn)行比較。
  • 0和-0是相等的
  • Infinity比其他任何數(shù)字都大(除了自身)
  • -Infinity比其他數(shù)字都小(除了自身)
  • 如果一個(gè)操作數(shù)轉(zhuǎn)換成數(shù)字之后是NaN,那么比較操作符總是返回false

在上面規(guī)則中,字符串比較需要注意:

  • 字符串比較是區(qū)分大小寫(xiě)的,所有的大寫(xiě)ascii字符都是小于小寫(xiě)的ascii字符
  • 對(duì)于數(shù)字和字符串比較,只有兩個(gè)操作數(shù)都是字符串時(shí),才會(huì)進(jìn)行字符串比較

in運(yùn)算符

in運(yùn)算符的左邊總是希望是一個(gè)字符串,右邊操作數(shù)總是希望是一個(gè)對(duì)象,如果右邊對(duì)象擁有左操作值的屬性名,會(huì)返回true

對(duì)象,會(huì)傾向查找屬性名

var point = { x:1, y:1};
"x" in point // => true, 對(duì)象擁有名為“x”的屬性
"z" in point // => false, 對(duì)象不存在名為"z"的屬性
"toString" in point // => true,對(duì)象繼承了默認(rèn)的toString()方法

數(shù)組,會(huì)傾向查找索引

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ù)是一個(gè)對(duì)象,右操作數(shù)標(biāo)識(shí)對(duì)象的類(lèi),如果左側(cè)的對(duì)象是右側(cè)類(lèi)的實(shí)例,則返回true,否則返回false

var d = new Date();
d instanceof Date;  // true,d是由Date()創(chuàng)建的
d instanceof Object; //  true,所有對(duì)象都是Object實(shí)例
d instanceof Number; // false, d不是Number的實(shí)例

邏輯表達(dá)式

邏輯運(yùn)算符是進(jìn)行布爾運(yùn)算使用的,主要有

  • && 邏輯與
  • || 邏輯或
  • ! 邏輯非

邏輯與(&&)

當(dāng)操作數(shù)都是布爾值時(shí),&&對(duì)兩個(gè)值進(jìn)行布爾與操作,第一個(gè)與第二個(gè)操作數(shù)都是true時(shí),才返回true,其中一個(gè)是false,就會(huì)返回false

當(dāng)操作數(shù)不都是布爾值時(shí),&&不一定會(huì)返回布爾值。

  • 邏輯與運(yùn)算符,首先計(jì)算左側(cè)的值,如果計(jì)算結(jié)果是假植,則整個(gè)表達(dá)式都是假植,因此會(huì)簡(jiǎn)單的返回左側(cè)操作數(shù)的值
  • 如果左側(cè)值是真值,那么整個(gè)表達(dá)式結(jié)果依賴(lài)于右側(cè)的值,因此,&&運(yùn)算符符會(huì)計(jì)算右側(cè)操作數(shù)的值,并且將其返回作為整個(gè)表達(dá)式的計(jì)算結(jié)果
var o ={ x:1 };
var p = null;
o && o.x; // =>1 ,o對(duì)象是真值,返回o.x
p && p.x; // => null ,p是假值,將其返回,不會(huì)計(jì)算p.x

上面那種行為,被稱(chēng)為 短路,這一特性非常有用,可以選擇性執(zhí)行代碼。 例如:
if ( a == b ) stop(); 等價(jià)于 ( a == b ) && stop();

邏輯或(||)

當(dāng)操作數(shù)都是布爾值時(shí),||對(duì)兩個(gè)操作數(shù)作布爾或運(yùn)算,兩個(gè)操作數(shù)有一個(gè)為真,返回true,兩個(gè)操作數(shù)都是假,才會(huì)返回false

當(dāng)操作數(shù)不都是布爾值,||不一定返回布爾值

  • 邏輯或運(yùn)算符,首先計(jì)算左側(cè)的值,如果計(jì)算結(jié)果是真值,則整個(gè)表達(dá)式都是真值,因此會(huì)返回這個(gè)真值
  • 否則再計(jì)算第二個(gè)操作數(shù)的值,再返回這個(gè)表達(dá)式的計(jì)算結(jié)果

||同樣是非常有用,比如從一組備選表達(dá)式中選出第一個(gè)真值表達(dá)式。這種做法經(jīng)常在函數(shù)體內(nèi),給參數(shù)提供默認(rèn)值

var max = max_width || preference.max_width || 500;

邏輯非(!)

! 運(yùn)算符是一元運(yùn)算符,放在一個(gè)單獨(dú)的操作數(shù)前,對(duì)操作數(shù)布爾值進(jìn)行求反

!運(yùn)算符首先將操作數(shù)轉(zhuǎn)換為布爾值,再進(jìn)行求反,最終只會(huì)返回true或者false

作為一元運(yùn)算符,優(yōu)先級(jí)非常高,并且和操作數(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á)式計(jì)算

js可以通過(guò)eval()來(lái)動(dòng)態(tài)判斷源代碼中的字符串,并且執(zhí)行

eval()只有一個(gè)參數(shù),如果傳入的參數(shù)不是字符串,直接返回這個(gè)參數(shù)。如果參數(shù)是字符串,則會(huì)把字符串當(dāng)成代碼進(jìn)行編譯。
如果編譯失敗,則返回一個(gè)語(yǔ)法錯(cuò)誤異常。如果編譯成功,則會(huì)執(zhí)行這段代碼,并且返回字符串最后一個(gè)表達(dá)式或者語(yǔ)句的值。
如果最后一個(gè)表達(dá)式或語(yǔ)句沒(méi)有值,則最終返回undefined

eval()使用來(lái)調(diào)用它的變量作用域環(huán)境,也就是說(shuō)查找變量會(huì)和局部作用域代碼完全一樣。

如果將eval()重命名為其他方式來(lái)調(diào)用,則使用全局對(duì)象作為上下文作用域,并且無(wú)法讀、寫(xiě)、定義局部變量

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); // 更改來(lái)局部變量,輸出"localchanged global"
console.log(g(),y); // 更改全局變量,輸出“l(fā)ocal globalchanged”

其他運(yùn)算符

條件運(yùn)算符(?:)

條件運(yùn)算符是唯一一個(gè)三元運(yùn)算符
(---1---) ? (---2---) : (---3---)

第一個(gè)操作數(shù)當(dāng)成布爾值,如果是真值,那么計(jì)算第二個(gè)操作數(shù),并返回結(jié)果。否則如果第一個(gè)操作數(shù)是假植,那么計(jì)算第三個(gè)數(shù),返回計(jì)算結(jié)果

x > 0 ? x : -x // 求x的絕對(duì)值

typeof運(yùn)算符

x typeof x
undefined "undefined"
null "object"
true or false "boolean"
任意數(shù)字或NaN "number"
任意字符串 "string"
任意函數(shù) "function"
任意內(nèi)置對(duì)象 "object"
任意宿主對(duì)象 由編譯器實(shí)現(xiàn)的字符串,但不是以上出現(xiàn)的字符串

這是一個(gè)一元運(yùn)算符,返回表示操作數(shù)類(lèi)型的一個(gè)字符串

x typeof x
undefined "undefined"
null "object"
true or false "boolean"
任意數(shù)字或NaN "number"
任意字符串 "string"
任意函數(shù) "function"
任意內(nèi)置對(duì)象 "object"
任意宿主對(duì)象 由編譯器實(shí)現(xiàn)的字符串,但不是以上出現(xiàn)的字符串

delete運(yùn)算符

delete運(yùn)算符,用來(lái)刪除對(duì)象屬性或者數(shù)組元素

var o = { x:1, y:2};
delete o.x; // 刪除一個(gè)屬性
"x" in o; // false,o對(duì)象中不存在屬性x

var a = [1,23,4];
delete a[2]; //刪除第三個(gè)元素
2 in a ; // false, 索引2的元素在數(shù)組中已經(jīng)不存在

delete刪除成功會(huì)返回true。然后不是所有屬性都可刪除的

  • 一些內(nèi)置核心和客戶端屬性是不能刪除的
  • 使用var語(yǔ)句生聲明的變量不能刪除
  • 通過(guò)function定義的函數(shù)和函數(shù)參數(shù)不能刪除。
var 0 = { x:1, y:2};
delete o.x; // true, 刪除對(duì)象屬性成功
typeof o.x; // undefined , 屬性不存在
delete o.x; // true, 刪除不存在的屬性,返回true
delete o; // false ,不能刪除var聲明變量

delete 1; // true, 參數(shù)不是一個(gè)左值,返回true
this.x = 1; // 定義全局對(duì)象的一個(gè)屬性
delete x; // 試圖刪除全局變量的屬性,非嚴(yán)格模式下,返回true
x; // 運(yùn)行時(shí)錯(cuò)誤,沒(méi)有定義x

void 運(yùn)算符

void 是一元運(yùn)算符,操作數(shù)照常計(jì)算,但是忽略計(jì)算結(jié)果并且返回undefined

這個(gè)操作符經(jīng)常用作客戶端URL-javascript:URL,通過(guò)使用void則讓瀏覽器不必顯示這個(gè)表達(dá)式計(jì)算結(jié)果

<a href="javascript:void window.open();">打開(kāi)一個(gè)新窗口</a>

逗號(hào)運(yùn)算符

逗號(hào)運(yùn)算符,首先計(jì)算左操作數(shù),然后計(jì)算右操作數(shù),最后返回右操作數(shù)的值。

總會(huì)計(jì)算左側(cè)的表達(dá)式,但計(jì)算結(jié)果忽略掉,也就是說(shuō),只有左側(cè)表達(dá)式有副作用時(shí),,才會(huì)使用逗號(hào)表達(dá)式讓代碼更通順。

經(jīng)常在for循環(huán)中使用

for(var i=0,j=10;i<j;i++,j--){
  console.log(i+j);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容