Skip to main content

[JS] JavaScript 運算子(Operator)

運算式與運算子 @ MDN

[TOC]

條件判斷(conditional statement)

  • 物件(object): 都是 true(空物件也是 true)
  • 陣列(array):陣列是一種物件,因此都會是 true(空陣列 [] 也是 true)
  • Undefined: 是 false
  • Null:是 false
  • 布林(Booleans):會根據 Boolean 值回
  • 數值(Numbers):除了 0, or NaN 會是 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 中定義變數時,casedefault 後面要加上大括號{ }

// 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 and default clauses that contain lexical declarations (e.g. let,const, function, and class). @ 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)

Conditional (ternary) operator @ MDN

// (條件) ? 條件成立 : 條件不成立
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 @ MDN

可以視為 || 的強化版。當使用 nullish coalescing operator (??) 時,只有當左側的值是 nullundefined 時,才會採用右側的值,否則會使用左側的值:

// 當左側的值是 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

/** 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)的效果。如果遇到奇數的話會無條件捨去。

其他

typeof

/**
* typeof 運算元;typeof (運算元)
**/

instanceof

/**
* object instanceof constructor
* 看看 object 是否為 constructor 所建構的實例
**/
function Foo() {}
const bar = new Foo();
console.log(bar instanceof Foo);

參考

運算式與運算子 @ MDN