【JavaScript 再入門】 基本構文編

## 前置き

今月で JavaScript 歴 1 年になりました。
Node.JS、バニラ js、React を使ってきました。
（JavaScript 以外にも、C#、Ruby、Swift とか少しずつ色々してます。）
その結果、「ソースを読めば何をしたいか理解できるようになってきた」

...そう思ってた時期が自分にもありました。
OSS のソースを読む機会があり、
その時、`prototype`がいきなり現れ、、、ナニソレオイシイノ状態に、、、

ということで改めて JavaScript を基礎から勉強しよう、と思い本記事を書くに至りました。

## ECMAScript

### 説明

ECMAScript は JavaScript の標準仕様書であり、この ECMAScript をもとに JavaScript が作られています。
ECMAScript は毎年バージョンアップされ、その都度、JavaScript の言語仕様が変わっています。
ES6 だの ES7 だの聞くかと思いますが、基本的には
`ECMAScript2015(2015年バージョン) と ES6`
`ECMAScript2016(2016年バージョン) と ES7`
はそれぞれ同意語のようです。

この ECMAScript ですが、ES6(つまり ECMAScript2015)で大きく変わりました。
const, let, 分割代入, class などなど。
今まで、JavaScript には無かった機能が一気に投入され、書き方が大きく変わりました。

本記事では両方と比較しながらまとめていきます。

## 変数の宣言 var, let, const

|                   | ソース                      | スコープ                                             | 特徴                                                                                            |
| :---------------- | :-------------------------- | :--------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| (無)              | `word = "HelloWorld"`       | 常にグローバルスコープ                               | 同名変数があった場合は上書き<br>`use strict`を使用した際はエラーが発生する                      |
| var               | `var word = "HelloWorld"`   | グローバルスコープ / 関数スコープ                    | 重複する変数が一つのスコープ内にあった場合、上書きされる                                        |
| let <br>【ES6】   | `let word = "HelloWorld"`   | グローバルスコープ / 関数スコープ / ブロックスコープ | 重複する変数が一つのスコープ内にあった場合、エラーが発生する                                    |
| const <br>【ES6】 | `const word = "HelloWorld"` | グローバルスコープ / 関数スコープ / ブロックスコープ | `let`の特徴に加え、定数である <br> プリミティブ型は書き換え不可<br>参照型の内部の値は書き換え可 |

## スコープ

JavaScript の変数のスコープは以下の 3 つです

| 種類               | 説明                           |
| :----------------- | :----------------------------- |
| グローバルスコープ | スクリプト全体から参照できる   |
| ローカルスコープ   | 関数の中からのみ参照できる     |
| ブロックスコープ   | ブロックの中からのみ参照できる |

ES6 で登場した、`let`,`const`を使用することでブロックスコープを定義することができます。
ブロックスコープを使用しないということは下記のようなコードがかけます。

```js
if (true) {
  var hello = "Hello World"
  console.log(hello) // Hello World
}
console.log(hello) // Hello World
```

予期せぬ動作を回避するために
ES6 で書ける環境では`var`ではなく、ブロックスコープを持つ`let`や`const`を使用することが推奨されています

#### 余談

※Swift 等の`let`、`var`とは全く意味が違うので注意！
var はバグの温床になるため、ES6 以上が使える場合は積極的に let,const を使うのが一般的なようです。

私はたまに swift で`let`で宣言したけど、書き換えできなかった
とかなるので。。。

## JavaScript のデータ型

JavaScript は動的型付け言語のため、Java や C#のように変数宣言時にデータ型が決まりませんが、型は存在します。

### 一覧

| 種類           | データ型     | 意味                                                                           |
| :------------- | :----------- | :----------------------------------------------------------------------------- |
| プリミティブ型 | number       | 数値を表す型                                                                   |
| プリミティブ型 | **_string_** | 文字列を表す型                                                                 |
| プリミティブ型 | boolean      | 真偽値(true / false)を表す                                                     |
| プリミティブ型 | symbol       | シンボル?を表す (次回?まとめます。。。)                                        |
| プリミティブ型 | null         | オブジェクトが存在しないことを表す型                                           |
| プリミティブ型 | undefined    | 値が未定義であることを指す型<br>例）未代入の変数、戻り値が未定義の関数の戻り値 |
| 参照型         | Object       | 上記以外                                                                       |

### 補足 プリミティブ型

プリミティブ型はメソッドを持たないデータ型のことです。
ですが、JavaScript では以下のようにかけます

```js
const hello = "javascript";
const uppperHello = hello.toUpperCase();
console.log(uppperHello); // JAVASCRIPT
```

これは、JavaScript が string 型(プリミティブ型)から string のラッパーオブジェクトである String オブジェクトに自動変換してくれているため、実行できます。

```js
(new String(hello)).toUpperCase()
```

## 【ES6】文字列へ変数を埋め込む \${expression}

```js
let name = "matsuda"
console.log(`彼は${name}です。`) // 彼はmatsudaです。
console.log(`彼は${20 + 4}歳です。`) // 彼は24歳です。
```

バッククォート「\`\`」と「\$」を使用することで文字列リテラルの中で変数や式を使用することができます。

[MDN テンプレート文字列](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/template_strings)

## 【ES6】分割代入 { user_id, user_name, ... } = { user_id:"0001", user_name: matsuda, user_old: 24 }

分割代入とは、配列 / オブジェクト から値を取り出し個別の変数に代入し直す JavaScript の構文のことです。

### オブジェクト

```js
const userInfo = {
  name: "matsuda-naoya",
  old: "24",
  birthplace: {
    country: "Japan",
    prefecture: "ehime"
  }
};

// --- ES5まで ---
// const name = userInfo.name;
// const prefecture = userInfo.birthplace.prefecture;
// const likeProgrammingLanguage = "JavaScript";
// const another = { old : userInfo.old}

// --- ES6から ---
const {
  name: userName, // 1 変数userNameにuserInfo.nameを代入
  birthplace: { prefecture }, // 2 変数prefectureにuserInfo.birthplace.prefectureを代入
  likeProgrammingLanguage = "JavaScript", // 3 変数likeProgrammingLanguageに"JavaScript"を代入
  ...another // 4 変数anotherに{old: "24"}オブジェクトを代入
} = userInfo;

  console.log(userName); // matsuda-naoya
  console.log(prefecture); // ehime
  console.log(likeProgrammingLanguage); // JavaScript
  console.log(another) // { old: "24"}
};
```

1. `変数名: 別名`と記載することで分割代入時に変数名を変更できる
1. `変数名: { 入れ子の変数名 }`と記載することで入れ子のオブジェクトも個別に展開することができる
1. `変数名 = リテラル`とすることで、分割対象のプロパティが存在しなかった場合、指定したリテラルで初期化する
1. `...変数名`とすることで分割代入によって展開されなかった残りの列挙可能なプロパティを指定した変数に代入する

### 配列

```js
const snsList = ["line", "twitter", "youtube", "facebook", "Instagram"];
// ES5まで
// const LINECorporation = snsList[0]
// const twitter = snsList[1]
// const faceBookInc = [snsList[3], snsList[4]]

// ES6から
const [
  LINECorporation,     // 1. 変数LINECorporationにsnsList[0]を代入
  twitter,             // 1. 変数twitterにsnsList[1]を代入
  ,      　            // 2. snsList[3]の値は無視する
  ...faceBookInc       // 3. snsListの残りの値をfaceBookIncに代入
] = snsList;
console.log(LINECorporation); // line
console.log(twitter); // twitter
console.log(faceBookInc); // ["facebook", "Instagram"]
```

1. `[変数名, 変数名] = 配列`と記載することで配列の Index 順に、宣言した変数に代入される
1. `, ,`と記載することでそのインデックスに応じた値は代入されない(無視される)
1. `...変数名`とすることで分割代入によって展開されなかった残りの値が指定した変数に代入される

[MDN 分割代入](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)

## false になる値(falsy)

以下は Boolean 型に変換された際に false になる値です。

- "", ``, '' (空文字)
- 0 (数値型のゼロ)
- NaN (Not a Number)
- null
- undefined

上記以外は**true**になります

JavaScript は動的型付けで、*if(hogehoge)*のように記載した場合は強制的に型変換が行われるため、以下のようなコードがかけます。

```js
if("") {
  // 実行されない
}
if(0) {
  // 実行されない
}
let emptyName;
if (emptyName) {
  // 実行されない
}

const name = "matsuda";
if (name) {
  console.log(name) // matsuda
}
```

[MDN Falsy](https://developer.mozilla.org/ja/docs/Glossary/Falsy)

## 論理演算子 ( && || ) とショートサーキット評価(短絡演算子)

JavaScript には以下の 3 つの論理演算子が存在します。

| 演算子            | 例                       | 説明                                                                                                                                                                                  |
| :---------------- | :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| && (AND)          | value1 && value2         | value1 が false とみなせる場合、value1 を返し、<br>true とみなせる場合は value2 の値を返す<br>すなわち、左右どちらも true の場合 true を返し、<br>左が false の場合 false を返す      |
| &#124;&#124; (OR) | value1 &#124;&#124; value2 | value1 が true とみなせる場合、value2 を返し、<br>false とみなせる場合は value1 の値を返す<br>すなわち、左右どちらも true の場合 true を返し、<br>左が false の場合、右の true を返す |
| ! (NOT)           | !value                   | 式が true とみなせる場合は false を返し、false とみなせる場合は true を返す                                                                                                           |

### ショートサーキット評価

論理演算子`&&`と`||`は左の式から右の式順で評価が行われ、左側の式を評価した際に最終評価が確定した場合は、右側の式は評価されません。
さらに、`&&`と`||`は Boolean 型以外も返却できるため、以下のような書き方ができます。

```js
  let emptyName;
  emptyName = emptyName || "初期値"  // 1
  console.log(emptyName) // 初期値

  let tempObj = {
    notEmpty: "空じゃないよ"
  };
  temp = tempObj && tempObj.notEmpty // 2
  console.log(temp) // 空じゃないよ
```

1. emptyName は`undefined`で`false`とみなすことができ、`||`の性質から、右辺の`初期値`が`emptyName`に代入される
1. tempObj は falsy な値でないため、`true`とみなすことができ、`&&`の性質から、右側の値が`temp`に代入される
   ※ 2 の書き方は直感的に理解しにくいため、三項演算子を使用した書き方や、デフォルト引数【ES6】で書く場合が多いとか...
   (この辺は関数編で詳細にまとめます...)

```js
// 三項演算子
temp = tempObj ? tempObj.notEmpty : ""


// 【ES6】デフォルト引数
function main(firstName, familyName = "Matsuda") {
  return firstName + familyName;
}
console.log(main("Naoya")); // NaoyaMatsuda
```

### オブジェクトの null チェック

`!`演算子を使用することで、以下の書き方ができます。

```js
let notEmptyObj = {
  name: "matsuda"
}
if (notEmptyObj) {
  // notEmptyObjに値がある場合(falsyな値でない)場合処理が実行
}

let emptyObj = undefined
if (!emptyObj) {
  // emptyObjがundefined(falsyな値の)場合処理が実行
}
```

## まとめ

JavaScript の基本構文についてまとめました。
冒頭の`prototype`はどこじゃいってなりそうですが、スミマセン。
いざ再学習し始めると想像以上に知らなかったことや詳細を理解していないことがたくさんあり、予想以上に時間がかかってしまいました。

関数やオブジェクトについては次回まとめることにします。

## 追記
まとめました！
[【JavaScript 再入門】 オブジェクトの初期化と列挙編](https://qiita.com/naoya_matsuda/items/ba69576132d2351e4efb)

## 参考

[改訂新版 JavaScript 本格入門～モダンスタイルによる基礎から現場での応用まで](https://gihyo.jp/book/2016/978-4-7741-8411-1)
[JavaScript の「&&」「||」について盛大に勘違いをしていた件](https://qiita.com/Imamotty/items/bc659569239379dded55)
[&#091;WIP&#093;JavaScript の入門書](https://jsprimer.net/)
[MDN web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript)