[JS] JavaScript 運算子(Operator)
運算式與運算子 @ MDN
[TOC]
條件判斷(conditional statement)
- 物件(object): 都是 true(空物件也是 true)
- 陣列(array):陣列是一種物件,因此都會是 true(空陣列
[]
也是 true) - Undefined: 是 false
- Null:是 false
- 布林(Booleans):會根據 Boolean 值回
- 數值(Numbers):除了
0
, orNaN
會是 false 外,其他都是 true - 字串(String):除了空字串
''
會是 false 之外,其他都是 true(字串中有空格也是 true)
code style
// 單行的 if 可以不用加上 {...}
if (lemons) console.log('hello');
16.1 Use braces with all multi-line blocks @ airbnb
- 不要在
else
中使用return
:
16.3 no-else-return @ airbnb
// bad
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// good
function foo() {
if (x) {
return x;
}
return y;
}
// bad
function cats() {
if (x) {
return x;
} else if (y) {
return y;
}
}
// good
function cats() {
if (x) {
return x;
}
if (y) {
return y;
}
}
- 當
if
當中的條件式太長的時候,可以換行並把比較運算子放在最前面(17.1 @ airbnb):
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc') &&
doesItLookGoodWhenItBecomesThatLong() &&
isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
比較運算子(comparison operator)
- 使用
===
或!==
其餘參數(rest parameter)
其餘運算字會幫助我們把輸入函式中的參數值變成陣列的形式(多個值 => 陣列):
let avg = function (...arr) {
console.log(arr); // [1,3,5,7,9]
};
console.log(avg(1, 3, 5, 7, 9));
展開語法(spread syntax)
展開運算子則是可以把陣列中的元素取出(陣列 => 多個值):
複製陣列(Copy an array)
var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4);
// arr2 becomes [1, 2, 3, 4]
// arr remains unaffected
連結陣列(concatenate arrays)
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2]; // [ 0, 1, 2, 3, 4, 5 ]
將陣列 代入函式中
let number = [1, 2, 3, 4, 5];
console.log(Math.max(...number)); // 5
console.log(...number); // 1,2,3,4,5
複製物件(Copy Objects)
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
// 使用 Object.assign() 會觸發 setters,而 spread syntax 不會
var clonedObj = { ...obj1 }; // Object { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 }; // Object { foo: "baz", x: 42, y: 13 }
邏輯運算子
keywords: short circuit boolean operator
double and &&
// 原則:如果前者為真,則回傳後者;如果前者為假,則回傳前者,後面的都不考慮
console.log(3 === 3 && 'apple' === 'apple'); // true(因為 'apple' === 'apple')
console.log(3 === 3 && 'apple'); // 'apple',如果自己為真,則回傳後者
console.log(3 === 3 && 'apple' && 'chicken'); // 'chicken'
console.log(3 === 3 && false && 'chicken'); // 'false',如果自己為假,就會回傳它自己
使用情境
// 使用情境:判斷前面的項目是不是都正確,如果是的話,在執行後者
callback && callback(); // 如果 callback 存在,則執行()
/**
* 如果 token.authenticate 存在則 secret = token.number
* 否則 secret = token.authenticate
**/
let secret = token.authenticate && token.number;
double or ||
// 原則:如果前者為真,則回傳前者,後面都不考慮;如果前者為假,則回傳後者
console.log(3 === 3 || false || 'chicken'); // true(因為 3 === 3)
console.log(3 === 4 || false || 'chicken'); // 'chicken'
// 使用時機:設定預設值時
let width = window.innerHeight || 300; // 如果 window.innerHeight 不存在,則 width 為 300
switch case
當需要在 switch 的 case 中定義變數時,case
和 default
後面要加上大括號{ }
:
// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {
// ...
}
break;
default:
class C {}
}
// good
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {
// ...
}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}
15.5 Use braces to create blocks in
case
anddefault
clauses that contain lexical declarations (e.g.let
,const
,function
, andclass
). @ airbnb
位元 NOT 運算子(波浪號)
任何 >=0
的值都會是非 0 的結果
/**
* 使用情境:用在判斷式
* 如果是 indexOf 回傳的值是 -1 表示找不到,那麼加上 ~ 之後會變 0 ,放在 if 裡面變成 false
**/
// 等同於 if(String.indexOf('e') >= 0){ ... }
if (~String.indexOf('e')) {
console.log('Find it');
}
// 用在正數無條件捨去,類似 Math.floor() 但是當裡面的數值為負數時則結果不同
console.log(~~1.45345); // 1
條件三元判斷式(ternary operator)
// (條件) ? 條件成立 : 條件不成立
const status = age >= 18 ? 'adult' : 'minor';
串連使用三元判斷式(conditional / ternary chains)
由於 ternary operator 從程式的最右邊開始看(right-associative),因此若串連起來的話,等同於 if...else if ... else if ... else ...
的用法:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
function example(…) {
return condition1 ? value1
: condition2 ? value2
: condition3 ? value3
: value4;
}
// Equivalent to:
function example(…) {
if (condition1) { return value1; }
else if (condition2) { return value2; }
else if (condition3) { return value3; }
else { return value4; }
}
例如:
const foo = (num: number): string => {
return num < 10 ? '< 10' : num < 20 ? '< 20 ' : num < 30 ? '< 30' : '>= 30';
};
// 等同於
const foo = (num: number): string => {
if (num < 10) {
return '< 10';
} else if (num < 20) {
return '< 20';
} else if (num < 30) {
return '< 30';
} else {
return '>= 30';
}
};
console.log(foo(5)); // '<10'
空值聯合運算子(nullish coalescing operator)
可以視為 ||
的強化版。當使用 nullish coalescing operator (??
) 時,只有當左側的值是 null
或 undefined
時,才會採用右側的值,否則會使用左側的值:
// 當左側的值是 undefined 或 null 時,則回傳右側的值
undefined ?? 'foo'; // foo
null ?? 'foo'; // foo
// 除了 undefined 或 null 之外,則都會回傳左側的值
false ?? 'foo'; // false
0 ?? 'foo'; // 0
optional chaining operator
可以視為物件取用屬性時 .
的強化版,使用 ?.
當左側的屬性不存在,即使繼續取用內部屬性也不會噴錯,而是得到 undefined
:
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
const dogName = adventurer.dog?.name;
dogName; // undefined,若 dog 屬性不存在
adventurer.someNonExistentMethod?.(); // undefined,若 someNonExistentMethod 方法不存在
可 以搭配 nullish coalescing operator 使用:
const dogName = adventurer.dog?.name ?? 'Daniel';
console.log(dogName); // 'Daniel'
delete
/**
* delete
* 假如 delete 運算子使用成功, 它會將物件或是 property 設定為 undefined。 delete 運算子會在運算成功時回傳 true ,失敗時回傳 false 。
* 一般定義的物件是無法用 delete 刪除(你可以用 delete 運算子來刪除隱式宣告的變數, 但不適用於宣告過的變數。)
* 因此比較適合用來刪除物件屬性
**/
delete objectName; // 宣告過就無法透過 delete 刪除
delete objectName.property; // 可以刪除
delete objectName[index];
/**
* object instanceof constructor
* 看看 object 是否為 constructor 所建構的實例
**/
function Foo() {}
const bar = new Foo();
console.log(bar instanceof Foo);
bitwise operator
- bitwise Operator @ MDN
- Bitwise Operators 3: The XOR Operation @ Youtube
- Bitwise Operators 4: The Logical Shift Operation @ Youtube
/** XOR Operator */
2 ^ 2; // 0
2 ^ 1; // 3, 2 的二進制是 10, 1 的二進制是 01,XOR 後變成 11,轉回 10 進制是 3
/** Shift Operator */
2 << 1; // 4,向左移動一位,2 x 2 = 2*(2**1)
3 << 1; // 6,向左移動一位,3 x 2 = 3*(2**1)
3 << 2; // 12,向左移動兩位,3 x 2 x 2 = 3*(2**2)
4 << 4; // 64,向左移動四位,4 x 2 x 2 x 2 x 2 = 3*(2**4)
/** right operator */
64 >> 1; // 32,向右移動一位,64 / 2 = 64/(2**1)
64 >> 4; // 4,向右移動一位,64 / 8 = 64/(2**4)
30 >> 1; // 15
30 >> 2; // 7,向右移動一位,30 / 4 = 30/(2**2) = 7.5 -> 小數後捨棄
- XOR Operations(
^
):特性是相同的值相加後會等於 0,可以搭配bitwise mask
作爲 key 使用。 - Logical Shift Operation(
>>
,<<
)- 透過 left shift operator(
<<
)所有的位數會向左移動 1 位,最右邊那位數會補 0,達到原數字 double(x 2)的效果 - right shift operator(
>>
)則相反,所有的位數會向右移動 1 位,最左邊那位會補 0,達到原數字除以 2(/ 2
)的效果。如果遇到奇數的話會無條件捨去。
- 透過 left shift operator(