すべての根底となる[[Truthy (JavaScript)|Truthy]]、[[Falsy (Elixir)|Falsy]]、[[Nullish (JavaScript)|Nullish]]について理解したうえで、いくつかの演算子を学びましょう。
## Reference
- [演算子 · JavaScript Primer \#jsprimer](https://jsprimer.net/basic/operator/)
## Lesson
### Truthy/Falsy/Nullish
[[Truthy (JavaScript)|Truthy]]と[[Falsy]]、[[Nullish (JavaScript)|Nullish]]は似て非なるものです。しっかり違いを把握しておきましょう。これを理解しなければ、このあとの話は理解できません。
| 値 | Truthy | Falsy | Nullish |
| ------------------------------------- | ------ | ----- | ------- |
| [[undefined (JavaScript)\|undefined]] | No | Yes | Yes |
| [[null (JavaScript)\|null]] | No | Yes | Yes |
| 0 or 0n | No | Yes | **No** |
| "" | No | Yes | **No** |
| [[NaN (JavaScript)\|NaN]] | No | Yes | **No** |
### 論理積演算子
[[論理積演算子 (JavaScript)|論理積演算子]]は、`a && b` としたとき `a` が [[Truthy (JavaScript)|Truthy]] であれば `b` を返し、そうでなければ `a` を返却する演算子です。
```js
"a" && "b"
// "b"
"a" && "b" && "c"
// "c"
"" && "b"
// ""
```
### 論理和演算子
[[論理和演算子 (JavaScript)|論理和演算子]]は、`a || b` としたとき `a` が [[Truthy (JavaScript)|Truthy]] であれば `a` を返し、そうでなければ `b` を返却する演算子です。
```js
"a" || "b"
// "a"
"a" || "b" || "c"
// "a"
"" || "b"
// "b"
```
### Null合体演算子
[[Null合体演算子 (JavaScript)|Null合体演算子]]は、`a ?? b` としたとき `a` が [[Nullish (JavaScript)|Nullish]] であれば `b` を返し、そうでなければ `a` を返却する演算子です。
```js
console.log("a" ?? "b");
// "a"
console.log("a" ?? "b" ?? "c");
// "a"
console.log("" ?? "b");
// ""
console.log(null ?? "b");
// "b"
console.log(undefined ?? "b");
// "b"
```
### 論理否定演算子
[[論理否定演算子 (JavaScript)|論理否定演算子]]は、`!a` としたとき `a` が [[Truthy (JavaScript)|Truthy]] であれば `false` を返し、そうでなければ `true` を返す演算子です。
```js
console.log(!true);
// false
console.log(!false);
// true
console.log(!"hoge");
// false
console.log(!"");
// true
console.log(!undefined);
// true
```
## Mission 1
#🙂NORMAL
以下のコードは関数の実装が間違っています。コードを修正してください。
```js
/**
* 引数がすべて空文字ではないことを確認します
* @param {string} str1
* @param {string} str2
* @param {string} str3
* @returns {boolean} 結果
*/
function notIncludesEmpty(str1, str2, str3) {
return str1 && str2 && str3;
}
```
%%
解答例
```js
/**
* 引数がすべて空文字ではないことを確認します
* @param {string} str1
* @param {string} str2
* @param {string} str3
* @returns {boolean} 結果
*/
function notIncludesEmpty(str1, str2, str3) {
return Boolean(str1 && str2 && str3);
}
```
%%
> [!hint]- Hint 1
> [[#論理積演算子]]の仕様を確認し、どのようなルールで何の[[データ型 (JavaScript)|データ型]]を返却するのか確認してみましょう。
## Mission 2
#🙂NORMAL
以下のコードは関数の実装が間違っており、`c` に空文字を指定した場合も `@` が結合されてしまいます。**コードの総文字数が変わらない**ように修正してください。
```js
/**
* 3つの文字列を結合します。
* cは省略可能であり、その場合は"@"として結合します。
*
* @param {string} a
* @param {string} b
* @param {string} [c="@"]
* @returns {string} 結合された文字列
*/
function join(a, b, c) {
return a + b + (c || "@");
}
```
%%
解答例
```js
/**
* 3つの文字列を結合します。
* cは省略可能であり、その場合は"@"として結合します。
*
* @param {string} a
* @param {string} b
* @param {string} [c="@"]
* @returns {string} 結合された文字列
*/
function join(a, b, c) {
return a + b + (c ?? "@");
}
```
%%
> [!hint]- Hint 1
> [[#論理和演算子]]の仕様を確認し、どのようなルールで何の[[データ型 (JavaScript)|データ型]]を返却するのか確認してみましょう。
## Mission 3
#😵HARD
以下のコードは関数の実装が間違っています。問題が発生する『不具合の概要』『期待値』『原因』『解決方法(コード)』を説明してください。
```js
/**
* moneyを渡すとおつりを返却します。
*
* - moneyが未指定(またはundefined or null)の場合はundefinedを返却します
* - moneyには数値型以外の値が入らないという前提があります
* - moneyが50未満の場合におつりがマイナスになることは許容します
*
* @param {number} money
* @returns {number|undefined} おつり
*/
function pay(money) {
if (!money) {
return undefined;
}
return money - 50;
}
```
%%
解答例
【不具合の概要】
`pay(0)` を指定すると `undefined` が返却されてしまう。
【期待値】
`-50` が返却されること。
【原因】
`!money` で [[論理否定演算子 (JavaScript)|論理否定演算子]]に `0` が指定されるが、`0` は [[Truthy (JavaScript)|Truthy]]ではない ([[Falsy (JavaScript)|Falsy]]である) ため、結果が `true` となり、if文の中で `undefined` が返却されるから。
【解決方法】
[[不等価演算子 (JavaScript)|不等価演算子]]を使って `undefined` or `null` を判定する。
```js
/**
* moneyを渡すとおつりを返却します。
*
* - moneyが未指定(またはundefined or null)の場合はundefinedを返却します
* - moneyには数値型以外の値が入らないという前提があります
*
* @param {number} money
* @returns {number|undefined} おつり
*/
function pay(money) {
if (money == null) {
return undefined;
}
return money - 50;
}
```
%%
> [!hint]- Hint 1
> [[#論理否定演算子]]が[[Falsy (JavaScript)|Falsy]]な値に対してどう振る舞うかを見直してみましょう。
> [!hint]- Hint 2
> [[📗TDQ-005 等価演算子と厳密等価演算子]] で学んだ内容を使います。
---
*NEXT* >> [[📗TDQ-008 関数]]