xia的小窩

一起來coding和碼字吧

0%

js-運算式與運算子

一般來說,我們常看到的運算子就是所謂的 + - * / 跟 %

1
2
let x = 5;
x++;

優先順序則是跟我們在算數學的時候一樣,有括號者優先

1
2
let x = 10;
x = ( x * 10 ) - x

比較運算子則有3種

  1. 嚴格相等
  2. 抽象 ( 寬鬆 ) 相等
  3. 與關係當成不同型態

現在我們可以來看一下 嚴格 跟 寬鬆 的差別

== 跟 === (相等運算子)

我們都知道 == 是一般的相等運算子,一般相等運算子 不限 兩邊差異,在處理兩邊數值不同型別的情況時都會對他們進行 強制轉型

1
2
3
4
5
6
7
8
9
10
11
console.log(false == "");
console.log(undefined == null);
console.log("" == '0');
console.log(false == []);
console.log(false == ![])

// true
// true
// false
// true
// true

嚴格的相等運算子

1
2
3
4
5
6
7
console.log(false === "");
console.log(undefined === null);
console.log("0" === 0);

// false
// false
// false

這個運算子會先比較兩邊的型別,然後再看數值,因此也被稱為全等於

物件的部分

1
2
3
4
5
console.log({} === []);
console.log([] === []);

// false
// false

emm…看起來答案都是 false 呢……

這是因為在JS裡,字串、數值、bool、undefined、null 這幾個型別都只能被概括的被稱為 純值 ,所以說 1 這個數字永遠都是 1 ,不應該有 1 === “1” 的想法。

當物件被創造後、賦值給變數時,變數所儲存的內容不是整個物件內容,而是該物件存放的記憶體位置。也就是說整個物件在創造後會分配到另一特定記憶體空間,然後變數拿到的只是記憶體位置,而不是整個物件的數值內容…….

所以在比較的時候不是比較物件內容,而是比較物件存放的記憶體位置……

1
2
3
4
5
let a = {};
let b = a;
console.log(a === b)

// true

上面的這個例子就很明顯了,當某物件創建完後,該物件的記憶體位置會存放在 變數a 內,而後我們再將變數 a的內容指派給變數 b,所以 a 跟 b 的內容都是同一記憶體位置……

! = 跟 ! = =

結果完全相反,不過 ! = 跟 == 一樣,會自動觸發轉型

1
2
console.log([] !== []) 
// true

大魚小魚等於

基本上我們都會使用這些運算子,那在這裡我們先補充一下 若兩邊型態不同 時的做法

  1. 如果兩邊都不是純值,則盡量轉為數值型別
  2. 如果都是字串,則按照 Unicode 比較
  3. 如果一邊是數值、一邊是字串,則將字串轉為數值比較
  4. 布林值、nulldefined 會被轉值為數值型別,布林值的false轉型 → 0 ,true → 1,null → 0
  5. unfined 轉型後會得到 NaN 的結果,而根據文件規範, NaN 與任何數值比較都會得到 false 的結果
1
2
console.log(5 > undefined)
// false

邏輯運算子

and 運算子 ( && )

1
2
console.log(1 && 0)
// 0

and 運算子很簡單,兩邊相同時為 true 其它為 false

or 運算子 ( || )

1
2
console.log(1 || 0)
// 1

當有一邊為 true 時就為 true,如果兩邊皆為 false 則為 false

not 運算子 ( ! )

1
2
console.log(!true)
// false

這個運算子是一元運算子,代表反向的邏輯。

位元運算子

運算子 說明 範例
^ xor 1 ^ 1 → 0
~ not 1100 → 0011
<< 左移 ob1010 << 1 → 0b10100
>> 有極右移 512 >> 3 → 64
>>> 補零右極 ~(512) >>> 3 → 2147483391

強制轉型

明確 ? 不明確 ?

好問題。一般來說我們在比較值的時候有2種作法

  1. 使用轉型 String( ) 、Number( )
  2. 如果自己沒有主動轉,JS會很貼心的幫你轉

上面的方法前者稱為 明確的轉型 ,後者稱為 隱含的轉型

如果我們使用 Number("2") ,這個動作就被稱為 明確的 轉型,不過因為 JS 是弱型別的語言( 弱型別的語言對數值運算型別的差異容忍度較高 ),所以數值型態能互相轉換,所以就有了 隱含 的轉型現象。

一般來說強制轉型分為三類。
我們先來看看第一類。

字串

明確轉型

1
String("2");

隱含強制轉型

1
2
String(123); // 明確
123 + ' ' // 隱含

其他類型

1
2
3
String(111)
String(-12.3)
String(null) // 'null'

布林值

明確強制轉型

1
Boolean()

隱含強制轉型

透過邏輯運算子以及 if 判斷式內的條件區塊來觸發

1
2
3
4
5
Boolean(3);             // 明確轉型
!!3 // 觸發
if ('test'){
//
}

反正不果怎麼轉都只有 true 跟 false 兩種結果

但是有些特定值不管怎麼轉都會只有 false or true 單一種結果,這些值會被稱作 Falsy Value / Trusy Value

Falsy Value

  1. 0
  2. NaN
  3. ‘ ’ ( 空字串 )
  4. False
  5. null
  6. undefined

Trusy Value

  1. 'false' ( 空字串以外的字串 )
  2. ( 空陣列 )
  3. { } ( 空物件 )
  4. function( ){ } ( 空函式 )

數值

明確轉型

1
2
3
Number(123)          // 123
Number(true) // 1
Number(" 2222sss ") // NaN

隱含強制轉型

透過運算子觸發 → 有4種

  1. 大、小運算子
  2. 算數運算子 ( 注意 + )
  3. 在任一其他類型的數值面前使用加法運算子 + 來觸發轉型
  4. 寬鬆的數值比較 ( ==!= )

物件轉布林

→ 任何非純值類零的數值,都會被轉型為 true

物件轉字串與數值

1
2
let a = {}
a.toString();

JS 根據 ECMAScript 的規範,使用一個叫做 ToPrimitive 的演算流程,這個流程分別使用 toStringValueOf 兩個方法搭配整個物件當作輸入值來判斷結果。而這兩個方法在所有的物件類型的數值上都可以呼叫,也可以透過複寫來自定。

通常物件都會有預設的 toString() 方法。如股宣告一個變數,直接呼叫其上面的 toString() 方法,就會得到 [object Object] 的字串結果,這是物件被轉為字串型別的預設值。

至於 ValueOf 方法,也是物件上的一個預設方法,這個方法同樣影響物件轉型的結果

1
2
let a = { test : 'mid' }
a.ValueOf()

恩…預設會回傳整個物件本身。