Yarnまとめ

Yarnについてまとめました。

Yarnについて理解すべきことは以下です。

  • Yarnはnpmより高速でセキュリティが強化されたJavaScriptのパッケージ管理ツール
  • Yarn自体はnpmを使ってパッケージをインストールする必要がある
  • Yarnの設定はnpm同様、package.jsonで行う
  • Yarnではpackage-lock.jsonではなく、yarn-lockを使う

Yarnとは

Yarnは、Facebookが開発したJavaScriptのパッケージ管理システム。

Yarnの他にJavaScriptのパッケージ管理システムにはnpmがあるが、Yanrはnpmに比べて高速でセキュリティが強化されている。

使い方はnpmと同じだが、コマンドが少し異なる。

Yarn自体をインストール

Yarnをインストールするにはnpmを使う。npmはNode.jsをインストールすると一緒にインストールされる。

npm install -g yarn

-gはグローバルにインストールすることで、PC全体で使えるようにすること。

グローバルの反対はローカルインストールであり、プロジェクトごとにインストールすること。ローカルの場合は-gをつけない。

基本的なコマンド

Yarnの基本的なコマンドは以下の通り。

コマンド 意味
yarn init package.jsonを作成する
yarn install パッケージをインストールする
yarn add パッケージをインストールする
yarn remove パッケージを削除する
yarn upgrade パッケージを更新する
yarn remove パッケージを削除する
yarn cache clean キャッシュをクリアする
yarn run [script] スクリプトを実行する
yarn -v yarnのバージョンを確認する

Yarnを使う流れ

Yarnは以下の流れで使う。

  1. プロジェクトにpackage.jsonがなければyarn initで作成する
  2. 必要なパッケージをインストールする
  3. パッケージを使って何らかの設定をしたり、機能を実装する・スクリプトを実行する

1. プロジェクトにpackage.jsonがなければyarn initで作成する

パッケージを管理するために必要なpackage.jsonを作成するためにyarn initを実行する。そのまま実行するといくつか質問を聞かれるが、-yをつけることで質問をスキップできる。

package.jsonの詳細についてはnpmの記事で説明している。

create-react-appやViteを使って環境構築を行なった場合は、自動的に作られる。

2. 必要なパッケージをインストールする

プロジェクトに必要なパッケージをインストールする。

インストールの仕方はyarn addを実行して直接パッケージをインストールする方法と、package.jsonyarn.lockに基づいてyarn installを実行してインストールする方法の2つある。

yarn addでインストールする方法

yarn addは主に特定のパッケージをインストールするために使われる。

# 本番環境で使うパッケージをインストールする
yarn add [パッケージ]

# -Dをつけると開発環境でのみ使うパッケージをインストールする
yarn add -D [パッケージ]

パッケージをインストールが完了すると、プロジェクトのルートにyarn.lockというファイルと、node_modulesというディレクトリが作られる。yarn.locknode_modulesについては後述。

yarn installでインストールする方法

yarn installは実行すると、package.jsonyarn.lockに記述されているパッケージとその依存関係がインストールされる。

この方法は開発者で環境を統一するために使う。

yarn install

package.jsondependenciesdevDependenciesにインストールしたいパッケージとそのバージョンを記述する。

dependenciesには本番環境で必要なパッケージを記述し、devDependenciesには開発環境で必要なパッケージを記述する。

3. パッケージを使って何らかの設定をしたり、機能を実装する・何らかのスクリプトを実行する

パッケージをインストールできたら、それらを使って任意の設定や機能を実装する。

他にもスクリプトを実行したりする。

スクリプトpackage.jsonscriptsに書かれているもので、プロジェクトのビルドやテストの実行など、何らかのコマンドを実行するためのもの。

スクリプトyarn run [script]で実行する。

ReactやNext.jsではさまざまなパッケージが必要になるので、パッケージのインストールやスクリプトを実行することで環境構築を行う。

yarn.lock

yarn.lockは、プロジェクトの依存関係とそのバージョンを追跡するための重要なファイルで、Yarnを使ってパッケージをインストールしたときに作られる。

このファイルには、プロジェクトにインストールされた各パッケージの正確なバージョンが記録される。これにより再現性が高まり、プロジェクトの開発環境を安定させることができる。

yarn.lockはnpmのpackage-lock.jsonにあたる。

node_modules

node_modulesは実際にインストールしたパッケージが格納されるディレクトリで、パッケージをインストールすると作られる。

Gitを使う場合、.gitignoreファイルにnode_modules/と記述してGitの管理から外す。

npm基礎まとめ

npmについてまとめました。

npmについて理解すべきことは以下です。

  • npmはJavaScript、Node.jsのパッケージ管理システム
  • npmを使うことで、パッケージの依存関係を解決して管理できたり、ビルドやテストなどのスクリプトを実行できる
  • npmはNode.jsをインストールすることで一緒にインストールされる
  • npmの基本的なコマンド
  • パッケージをインストールする方法は、npmのコマンドで直接インストールする方法と、package.jsonに記述してコマンドを実行する方法の2種類ある
  • パッケージはシステム全体で使えるようにするグローバルインストールと、プロジェクト内で使うためのローカルインストールがある
  • npm i--save-dev-Dをつけて実行すると、開発時のみ使うパッケージをインストールし、オプションをつけないと主に本番環境で使うパッケージをインストールする
  • package.jsonはnpmの設定ファイルで、プロジェクトの情報や、インストールしたパッケージのリスト、スクリプトなどが記述される
  • package-lock.jsonはインストールされたパッケージのバージョンや依存関係が記述されるファイルで、基本的に直接編集しない
  • package-lock.jsonディレクトリに存在する状態でnpm iを実行することで、パッケージを再現できる
  • 実際にインストールされたパッケージはnode_modulesに格納される
  • パッケージをインストールするときのバージョン指定の記法
  • npxというコマンドを使うことで、ローカルにパッケージがインストールされてなくても一時的にパッケージを実行できる

npmとは

npmとはNode.jsのパッケージ管理システム。JavaScriptでも使えて、ReactやNext.jsなどを使うためにも必須のツール。

パッケージとは、何らかの機能がまとまったものでライブラリともいう。パッケージ管理システムはそれらのパッケージをインストールしたり、削除したりできるツール。

npmを使う目的

npmを使う主な目的は以下のもの。

  • 依存関係を解決しながらパッケージを管理する
  • package.jsonを使って開発者同士で必要なパッケージを揃える
  • スクリプトの実行

依存関係とは、Aというパッケージを使うためには別のBやCというパッケージが必要であるというパッケージ同士の関係のこと。

npmが使われる前は必要になるすべてのパッケージを1つずつインストールしなければならなかったが、npmによって依存関係も含めてインストールできるようになった。

package.jsonスクリプトについては後述。

インストール

npmはNode.jsをインストールすると一緒にインストールされて使えるようになる。

Node.jsはnodenvというNode.jsをインストールするためのツールを使うのがおすすめ。

nodenvはプロジェクトごとでインストールするNode.jsのバージョンを切り替えることができる。

npmの基本的なコマンド

コマンド 意味
npm init npmを初期化して、package.jsonを作成する
npm init -y npm init実行時に聞かれる質問をスキップして初期化する
npm install [package] または npm i [package] パッケージをインストールする
npm i -g [package] パッケージをグローバルにインストールする
npm i --save-dev [package] または npm i -D [package] 開発時に必要なパッケージをインストールする
npm remove [package] パッケージを削除する
npm run [script] npm scriptを実行する
npm update [package] 特定のパッケージのバージョンを最新の安定版に更新する(package-lock.jsonのバージョンは更新しない)
npm upgrade 全てのパッケージのバージョンを最新の安定版に更新し、package-lock.jsonのバージョンも更新する
npm -v npmのバージョンを確認する

グローバルインストールとローカルインストール

npmのパッケージをインストールするとき、npm i -gでシステム全体にインストールするグローバルインストールと、npm iでプロジェクト内にインストールするローカルインストールの2種類の方法がある。

基本的にはローカルインストールを使う。

package.jsonとは

package.jsonとは、npmの設定ファイル。

package.jsonnpm initを実行すると作られる。

デフォルトでは以下の内容で作られる。

{
  "name": "react-environment-practice",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

name

nameはプロジェクトの名前を記述する。

version

versionはプロジェクトのバージョンを指定する。

description

descriptionはプロジェクトの説明を記述する。

main

mainはパッケージが外部に公開されたときに、どのファイルがそのパッケージのメインとなるファイルであるかを指定する。

scripts

scriptsはプロジェクトで実行可能なスクリプトを指定する。

npm run [script]とすることで、スクリプトを実行できる。

スクリプトを使うことで、ビルドやテストなどのコマンドを設定して実行することができる。

dependencies

dependenciesnpm iでインストールしたパッケージが記述される。

devDependencies

devDependenciesnpm i -Dでインストールした開発時のみに必要なパッケージが記述される。

主にビルドやテスト、デバッグなどに使うパッケージは-Dをつけてインストールする。

keywords

keywordsはプロジェクトに関連するキーワードのリストを指定するためのもの。

author

authorはプロジェクトの作者の名前が記述される。

license

licenceはプロジェクトのライセンスを指定する。

パッケージのバージョンについて

パッケージをインストールするときにはバージョンを指定することができる。記号を使うことでさまざまなバージョンの指定の仕方ができる。

npmのパッケージのバージョンは3つの数字をピリオドで区切る。 3つの数字はそれぞれ[major.minor.patch]という意味を持つ。これをセマンティックバージョンという。

majorは互換性のない大規模な変更が行われた場合に数字が上がる。

minorは後方互換性のある機能の追加や変更が行われたときに数字が上がる。

patchはバグの修正や既存の機能に対する小さな変更などが行われたときに数字が上がる。

# バージョンを指定しないと最新のバージョンがインストールされる
npm i yarn

# 指定したバージョンがインストールされる
npm i yarn@1.0.0

# 指定したバージョンより新しい最新のバージョンがインストールされる
npm i yarn@>1.0.0

# 指定したバージョンより古いもので最新のバージョンがインストールされる
npm i yarn@<1.0.0

# 指定したバージョン以上の最新のバージョンがインストールされる
npm i yarn@>=1.0.0

# 指定したバージョン以下の最新のバージョンがインストールされる
npm i yarn@<=1.0.0

# マイナーバージョンが固定された範囲でのインストールを指定する
npm i yarn@~1.0.0 # 1.0.0 ~ 1.1.0の中で最新のものがインストールされる

# マイナーバージョンとパッチバージョンが固定された範囲でのインストールを指定する
npm i yarn@^1.0.0 # 1.0.0 ~ 2.0.0未満の範囲の中で最新のものをインストールする

package-lock.jsonとは

package-lock.jsonnpm i実行時にインストールしたパッケージのバージョンや依存関係が記述されるファイルで、基本的に触らない。

package-lock.jsonを使ってnpm iでパッケージをインストールすることで、別の環境でも必要なパッケージとバージョンを再現でき、環境を統一できる。

node_modules

node_modulesnpm i実行時に作成される、インストールしたパッケージが実際に格納されるディレクトリ。

node_modulesnpm iを実行すると作成できるので、Gitでバージョン管理する場合、.gitignoreファイルにnode_modulesを記述し、Gitの管理から外す。

npx

npxはローカルにインストールされていないパッケージを一時的に実行するコマンド。

# 使用例
npx create-react-app my-app

上記のようにnpxでコマンドを実行することで、create-react-appをインストールせずに使える。

コンピュータの基礎

コンピュータの基礎についてまとめました。

コンピュータの基礎について理解すべきことは以下です。

  • コンピュータは情報を処理する機械
  • コンピュータは入力→処理→出力の流れで情報を処理する
  • コンピュータはどんな情報も最終的には0と1で判断する
  • コンピュータはハードウェアとソフトウェアとプログラムで構成される
  • ハードウェアは主に入力装置、出力装置、記憶装置、制御装置、演算装置の5大装置で構成される
  • コンピュータの中で処理を行うのがCPUであり、CPUは制御装置と演算装置にあたる
  • プログラムによってCPUが処理を実行する
  • 記憶装置にあたるのがメモリとハードディスクで、メモリはデータを一時的に記憶し、ハードディスクは長期的に記憶する
  • ソフトウェアは基本ソフトウェアであるOSと、応用ソフトウェアであるアプリケーションがある
  • ハードウェアとソフトウェアを連携させるのがOS
  • コンピュータを動かすための命令がプログラム
  • コンピュータは0と1しか理解できないので、人間がわかりやすいように命令を書くためのものがプログラミング言語

コンピュータとは

コンピュータは情報を処理する機械。

コンピュータの情報処理の仕方

コンピュータが処理する情報は、文字や数字、画像、音声、ビデオなど様々なものがあるが、コンピュータはどんなデータも0と1の電気信号で処理する。

これはコンピュータの内部が電子回路によって構成されていて、電子のオンとオフの状態が0と1に対応しているためである。

0と1という形式によってコンピュータの内部の処理がシンプルで効率的なものになるため、様々な用途で使うことができる。

コンピュータが行うこと

コンピュータはアプリを作ったり、ゲームをしたり、音楽を聴いたりと様々なことを実現できるが、コンピュータが行うことは本質的には入力→処理→出力を実行することである。


また情報の処理は、加工、蓄積・検索、伝達の3つに分類される。

加工は、情報を計算したり、並び替えたりすること。

蓄積・検索は、情報を集めて、その中から検索すること。

伝達は、情報を送信、受信して、見聞きできること。

ハードウェアとソフトウェアとプログラム

コンピュータは物理的な機械であるハードウェア、OSやアプリケーションのような目に見えず触ることもできないソフトウェア、コンピュータに対する命令であるプログラムによって成り立つ。

これらはどれが欠けてもコンピュータとして成り立たないものである。

ハードウェアの基本的な構成

ハードウェアは入力装置、出力装置、制御装置、演算装置、記憶装置の5大装置で構成される。

入力装置はマウスやキーボードのようなユーザーがコンピュータに対して入力を行う装置である。

出力装置はディスプレイやプリンターなどのコンピュータの処理結果を出力する装置である。

制御装置と演算装置はCPUにあたり、記憶装置はメモリとハードディスクにあたる。

CPU

CPUはコンピュータの脳みそのようなもので、5大装置の制御装置と演算装置にあたる。

制御装置は、コンピュータ内の全体的な動作を制御し、命令の取得や解読、実行などを行うための装置。

演算装置は、コンピュータでの算術演算や論理演算を行うための装置。

制御装置と演算装置によって、プログラムの命令を解釈して実行しデータを処理することができる。

メモリ

メモリは一時的に情報を保存する記憶装置。記憶装置には主記憶装置と補助記憶装置があり、メモリは主記憶装置である。

CPUはメモリに保存されたデータを使って処理を行う。

メモリの容量が多いほど一度に大量の処理をこなせる。


メモリにはRAMとROMという種類がある。

RAM(Random Access Memory)は自由にデータの読み書きができるが、電源を切るとデータが消去されてしまうメモリ。主にプログラムの実行プログラムの実行や作業領域のために使う。

ROM(Read Only Memory)は読み出し専用だが、電源を切ってもデータを保存できるメモリ。システム情報や不変のプログラムを保存するために使う。

ハードディスク

ハードディスクは長期的に情報を保存する記憶装置。主記憶装置のメモリに対して、ハードディスクは補助記憶装置である。

ソフトウェアの種類

ソフトウェアには基本ソフトウェアであるOSと、応用ソフトウェアであるアプリケーションがある。

OS

OSはオペレーションシステムのことで、ハードウェアとソフトウェアを仲介し、コンピュータの基本的な操作を提供するソフトウェア。基本ソフトウェアともいう。


OSによってハードウェアの管理や、入出力デバイスの制御、ファイルとディレクトリによるデータの管理、GUICUIなどのインタフェースの提供などが行われ、ユーザーがコンピュータを操作できるようになる。

アプリケーション

アプリケーションはコンピュータで何をするのかを実現するソフトウェアで、応用ソフトウェアともいう。

OSはアプリケーションを動かすための土台になる。

プログラム

プログラムはコンピュータに対する命令である。

しかし命令といってもコンピュータは0と1の電気信号しか理解できず、0と1だけを使って人間がプログラムを書くのは困難。そこで作られたのが人間でも理解しやすいプログラミング言語である。ちなみに0と1を機械語ともいう。


プログラミング言語機械語に近いアセンブリ言語と、人間が理解しやすい高級言語に分類され、高級言語にはJavaC言語など様々な種類がある。

アセンブリ言語高級言語もそのままではコンピュータは理解できないため、アセンブリ言語ではアセンブラというプログラムが、高級言語ではインタプリタコンパイラといったプログラムがコンピュータが理解できる機械語に翻訳する。

インタプリタは1行ずつ翻訳し、コンパイラはまとめて翻訳する。

よく使うショートカットキーまとめ

自分がよく使うアプリのショートカットキーをまとめておきます。(随時更新)

Mac

キー 操作
cmd+C コピー
cmd+V ペースト
cmd+X 切り取る
cmd+A 全選択
cmd+S 保存する
cmd+Z 操作を取り消す
cmd+shift+Z 操作の取り消しを取り消す
cmd+shift+5 スクリーンショットまたは録画
cmd+tab 表示しているアプリの切り替え

Google Chrome

キー 操作
cmd+T 新規タブを作成
cmd+W タブを削除
cmd+shift+T 削除したタブを復元
cmd+R ブラウザをリロード
cmd+L アドレスバーにフォーカス
cmd+, 設定を開く
cmd+Y 履歴を開く
fn+F12 開発ツールを開く
ctrl+tab 左のタブに移動

Vimium

キー 操作
k 上にスクロール
j 下にスクロール
gg ページの一番上に移動
G ページの一番下に移動
t 新規タブを作成
x タブを削除
X タブを復元
r リロード
f 現在のタブでリンクを開く
F 新しいタブでリンクを開く

VSCode

キー 操作
cmd+C 一行をコピー or 選択範囲をコピー
cmd+A 全選択
cmd+V 貼り付け
cmd+X 一行を切り取り or 選択範囲を切り取り
cmd+B サイドバーを開閉
cmd+Z 操作を取り消す
cmd+Z 操作を取り消す
cmd+D 単語を選択(同じ単語は複数選択できる)
cmd+F ファイル内で文字列を検索
cmd+L 一行ずつ下を選択
cmd+J ターミナルの開閉
cmd+P ファイルを検索
cmd+W タブを閉じる
cmd+shift+T 閉じたタブを再度開く
cmd+, 設定を開く
cmd+shift+P コマンドパレットを開く
cmd+N エクスプローラーで新規ファイルを作成
cmd+shift+N エクスプローラーで新規フォルダを作成
cmd+shift+H 検索と置換
cmd+shift+E エクスプローラーとエディタを移動
ctrl+tab 右にタブ移動
ctrl+K 一行削除
ctrl+H 左に1文字削除
ctrl+D 右に1文字削除
ctrl+P カーソルを上に移動
ctrl+F カーソルを右に移動
ctrl+N カーソルを下に移動
ctrl+B カーソルを左に移動
ctrl+A カーソルを一番左に移動
ctrl+E カーソルを一番右に移動
option+クリック マルチカーソル
option+↑↓ 行を上下に移動
shift+option+↑↓ 行または選択範囲を上下のどちらかに複製

Macを買った時に設定すること(自分用)

Macが急に壊れて買い替えることになり、一から設定やアプリのインストールをして面倒だったので、今後も買い替えた時のために行ったことをまとめておきます。(順次追加)

Mac本体の設定

カーソルの移動速度を速くする

システム設定→トラックパッド→軌跡の速さを一番速いにする

一番初めに設定する。

キーの速度を速くする

システム設定→キーボード→キーのリピート速度を一番速くする システム設定→キーボード→リピート入力認識までの時間を一番短くする

ディスプレイを常にNightShiftの状態にする

システム設定→ディスプレイ→NightShift...→スケジュールをカスタムに指定→開始を3:00、終了を2:59を指定

Spotlightを使わないように設定

Raycastを使うため、Spotlightを使わないように設定する。

システム設定→キーボード→キーボードショートカット→Spotlight→Spotlight検索を表示のチェックを外す

システム設定→SiriとSpotlight→Spotlightのプライバシー...→+をクリック→Macintosh HDを追加

低電力モードにする

システム設定→バッテリー→低電力モードを「常」に指定

USキーボードの設定

USキーボードを買って、デフォルトだとJISで使っていたキーバインドや日本語が使えないので変更。

変更にはKarabiner-Elementsというアプリを使う。

公式サイトhttps://karabiner-elements.pqrs.org/

commandで日本語入力

USキーボードでは日本語入力ができないので設定。

まず日本語環境向けの設定をインストールする。

Karabiner-Elementsを開く→Complex Modifications→Add ruleをクリック→Import more rules from the Internet(Open a web browser)をクリック→For Japanese(日本語環境向けの設定)(rev 6)のImportをクリック

Karabiner-Elementsを開く→Complex Modifications→Add ruleをクリック→「コマンドキーを単体で押した時に、英数・かなキーを送信する。(左コマンドキーは英数、右コマンドキーはかな)(rev 3)」をEnableにする

コロンとセミコロンの変更

Karabiner-Elementsを開く→Complex Modifications→Add ruleをクリック→Import more rules from the Internet(Open a web browser)をクリック→「Exchange semicolon and colon」のImportをクリック

Karabiner-Elementsを開く→Complex Modifications→Add ruleをクリック→「Exchange semicolon and colon」をEnableにする

ReactやRailsではセミコロンはあまり使わないのでデフォルトでコロンを入力するように設定。

{}との変更

Karabiner-Elementsを開く→Complex Modifications→Add ruleをクリック→Import more rules from the Internet(Open a web browser)をクリック→「Exchange {} and 」のImportをクリック

Karabiner-Elementsを開く→Complex Modifications→Add ruleをクリック→「Exchange {} and []」をEnableにする

使う頻度が高い{}をデフォルトで入力できるようにする。

caps lockとcontrolの変更

あまり使わないcaps lockとショートカットキーでよく使うcontrolの位置を反対にして、JISキーボードのようにする。

これはMacのシステム設定で変更する。

システム設定→キーボード→キーボードショートカット...→修飾キー→Caps lockキーをcontrolに指定する、ControlキーをCaps lockに指定する

Homebrew

HomebrewはMacOSのパッケージマネージャー。

公式サイトhttps://brew.sh/ja/

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

コマンド実行後はメッセージに従う。

実行するシェルスクリプト

適当にsetup.shファイルを作ってインストール作業を自動化する。

brew install --cask google-chrome
brew install --cask visual-studio-code
brew install --cask rectangle
brew install --cask raycast
brew install --cask warp
brew install --cask docker
brew install neovim
brew install nodenv
brew install rbenv ruby-build
brew install go peco ghq
brew install gh
brew install mas

Google Chrome

標準で使うブラウザ。MacのデフォルトのブラウザをGoogle Chromeに変更する。

ブックマーク

以下のサイトをブックマークしておく。

拡張機能

OneTab

タブをまとめてメモリを削減できる拡張機能

https://chrome.google.com/webstore/detail/onetab/chphlpgkkbolifaimnlloiipkdnihall?hl=ja

拡張機能→キーボードショートカット→OneTabの「現在のタブをOneTabに送る」をctrl+tに設定しておく。

DeepL翻訳

選択した部分を翻訳できる拡張機能

https://chrome.google.com/webstore/detail/deepl-translate-reading-w/cofdbpoegempjloogbagkncekinflcnj?hl=ja

React Developer Tools

Reactの開発ツール。

https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ja

AutoPagerize

ページネーションではなく、スクロールするだけで次のページを表示する拡張機能

https://chrome.google.com/webstore/detail/autopagerize/igiofjhpmpihnifddepnpngfjhkfenbp?hl=ja

Vimium

GoogleChromeVimのように扱える拡張機能

https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb?hl=ja

BlockSite

Youtubeなどの無駄な時間を費やすサイトをブロックするためにインストールする。

https://chrome.google.com/webstore/detail/blocksite-block-websites/eiimnmioipafcokbfikbljfdeojpcgbh?hl=ja

Raycast

Raycastは無料で使えるランチャーツール。

公式サイトhttps://www.raycast.com/

Homebrewでインストールするなら以下のコマンドを実行。

Raycastを開くコマンドを設定

Raycastを開く→Raycast Hotkeyをoption+Spaceに指定する。

Hotkeyを設定

Raycast→Extension→Record Hotkeyに指定したいキーを入力する

アプリ Hotkey
Google Chrome ctrl+G
Search recent projects(Visual Stadio Codeの拡張機能をインストール) ctrl+V
Warp ctrl+I

Warp

以前はターミナルはiterm2を使っていたが、Warpが良さそうなのでインストール。これに関しては良さそうなものが出たら変わりそう。

公式サイトhttps://www.warp.dev/

前はiterm2にoh-my-zshやtmuxを追加でインストールしていたけど、Warpはデフォルトでタブの分割や過去のコマンドの実行、コマンドの補完ができるので、そのまま使えそう。

Rust製で動作が速いらしい。

Rectangle

無料で使える画面を分割するアプリ。

公式サイトhttps://rectangleapp.com/

VSCode

エディタ。

公式サイトhttps://code.visualstudio.com/

基本設定

  • Auto SaveをafterDelay

拡張機能

ショートカットキー

一行削除をctrl+kに変更。 エクスプローラーでのファイルの作成をcmd+n、フォルダの作成をcmd+shift+nに変更。

スニペット

拡張機能を使ってもいいけど、スニペットを作っておく。

{
    "console.log": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "cl",
        "body": [
            "console.log($1)"
        ],
 },
    "const": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "c",
        "body": [
            "const $1 = $2"
        ],
 },
    "let": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "l",
        "body": [
            "let $1 = $2"
        ],
 },
    "typescript const": {
        "scope": "typescript,typescriptreact",
        "prefix": "tc",
        "body": [
            "const $1: $2 = $3"
        ],
 },
    "typescript let": {
        "scope": "typescript,typescriptreact",
        "prefix": "tl",
        "body": [
            "let $1: $2 = $3"
        ],
 },
    "if": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "i",
        "body": [
            "if ($1) {",
            "\t$2",
            "}"
        ],
 },
    "map": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "m",
        "body": [
            "map(($1) => {",
            "\t$2",
            "})"
        ],
 },
    "import": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "im",
        "body": [
            "import { $1 } from '$2'"
        ],
 },
    "export": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "ex",
        "body": [
            "export $1"
        ],
 },
    "arrow function": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "af",
        "body": [
            "const $1 = ($2) => {",
            "\t$3",
            "}"
        ],
 },
    "function components": {
        "scope": "javascript,javascriptreact",
        "prefix": "fc",
        "body": [
            "export const $1 = ($2) => {",
            "\t$3",
            "\t",
            "\treturn ($4)",
            "}"
        ],
 },
    "typescript function components": {
        "scope": "typescript,typescriptreact",
        "prefix": "tfc",
        "body": [
            "export const $1: VFC<$2> = ($3) => {",
            "\t$4",
            "\t",
            "\treturn ($5)",
            "}"
        ],
 },
    "props": {
        "scope": "javascriptreact,typescriptreact",
        "prefix": "pr",
        "body": [
            "const { $1 } = props"
        ],
 },
    "ternary operator": {
        "scope": "javascript,typescript,javascriptreact,typescriptreact",
        "prefix": "to",
        "body": [
            "$1 ? $2 : $3"
        ],
 },
    "useState": {
        "scope": "javascriptreact,typescriptreact",
        "prefix": "us",
        "body": [
            "const [$1, set$2] = $3"
        ],
 },
    "useCallback": {
        "scope": "javascriptreact,typescriptreact",
        "prefix": "ucb",
        "body": [
            "$1(($2) => {",
            "\t$2",
            "}, [$4])"
        ],
 },
    "useMemo": {
        "scope": "javascriptreact,typescriptreact",
        "prefix": "um",
        "body": [
            "$1(($2) => {",
            "\t$2",
            "}, [$4])"
        ],
 },
    "useEffect": {
        "scope": "javascriptreact,typescriptreact",
        "prefix": "ue",
        "body": [
            "$1(($2) => {",
            "\t$2",
            "}, [$4])"
        ],
 },
    "type": {
        "scope": "typescript,typescriptreact",
        "prefix": "ty",
        "body": [
            "type $1 = {",
            "\t$2 : $3",
            "}"
        ],
 },
}

Docker

Dockerは開発環境の構築に使うツール。

公式サイトhttps://www.docker.com/get-started/

NeoVim

MacにはデフォルトでVimがインストールされているが、より新しいNeoVimをインストールする。

公式サイトhttps://neovim.io/

nodenv

nodenvはプロジェクトごとに異なるバージョンのnodeをインストールできるツール。

公式サイトhttps://github.com/nodenv/nodenv

インストールしたら以下のコマンドを実行する。

echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(nodenv init -)"' >> ~/.zshrc

rbenv ruby-build

rbenvはRubyのバージョンを管理するツール。

公式サイトhttps://github.com/rbenv/rbenv

インストールしたら以下のコマンドを実行する。

rbenv init

go peco ghq

pecoとghqというツールを使うことで、ターミナルからGithubリポジトリを管理しやすくする。

pecoとghqを使うためにgoも必要なのでインストールする。

参考https://zenn.dev/obregonia1/articles/e82868e8f66793

gh

ghはGithubCUIで操作するためのコマンド。

公式サイトhttps://github.com/cli/cli#installation

mas

HomebrewからApple Storeのアプリをインストールできるようにするためのツール。

エイリアス設定

zsh、homebrew、git、docker、npm、yarn、npxのコマンドのエイリアスを作成。基本は単語、オプションの頭文字を使用。

vim ~/.zshrcを実行し、以下のコードを記述。

# zsh alias
alias v='nvim'
alias vz='nvim ~/.zshrc'
alias sz='source ~/.zshrc'

# brew alias
alias bi='brew install'
alias bic='brew install --cask'
alias bug='brew upgrade'
alias bud='brew update'
alias bl='brew list'
alias bui='brew uninstall'
alias bd='brew doctor'

# git alias
alias g='git'
alias gi='git init'
alias ga='git add'
alias ga.='git add .'
alias gc='git commit'
alias gcm='git commit -m'
alias gca='git commit --amend'
alias gb='git branch'
alias gba='git branch -a'
alias gbd='git branch -d'
alias gch='git checkout'
alias gchb='git checkout -b'
alias gps='git push'
alias gpso='git push origin'
alias gpl='git pull'
alias gplr='git pull --rebase'
alias gs='git status'
alias gl='git log'
alias glo='git log --oneline'
alias gd='git diff'
alias gm='git merge'
alias gcl='git clone'
alias gf='git fetch'
alias gt='git tag'
alias gtd='git tag -d'
alias grm='git remote'
alias grmv='git remote -v'
alias grma='git remote add'
alias grmrm'git remote rm'
alias grs='git reset'
alias grsh='git reset --hard HEAD^'
alias grb='git rebese'
alias grf='git reflog'
alias grv='git revert'
alias gcp='git cherry-pick'
alias gss='git stash'
alias gssl='git stash list'
alias gssp='git stash pop'

# docker alias
alias di='docker images'
alias drmi='docker rmi'
alias drm='docker rm'
alias dr='docker run'
alias dp='docker ps'
alias dpa='docker ps -a'
alias dcp='docker compose ps'
alias dcpa='docker compose ps -a'
alias dcl='docker compose log'
alias dcd='docker compose down'
alias dce='docker compose exec'
alias dcr='docker compose run'
alias dcrr='docker compose run --rm'
alias dc='docker compose up'
alias dcud='docker compose up -d'
alias dcudb='docker compose up -d -b'
alias dcb='docker compose build'
alias dcbnc='docker compose build --no-cache'
alias dvl='docker volume ls'
alias dvr='docker volume rm'
alias dsp='docker system prune'
alias dsd='docker system diff'
alias dbp='docker builder prune'

# npm alias
alias ni='npm i'
alias niy='npm init -y'
alias nu='npm uninstall'
alias nr='npm run'
alias ns='npm start'
alias nt='npm test'

# yarn alias
alias ya='yarn add'
alias yr='yarn remove'
alias yi='yarn install'

# npx
alias ncra='npx create-react-app'
alias ncratt='npx create-react-app --template typescript'

記述したら:wqで保存して、source ~/.zshrcを実行して設定を反映する。

JavaScriptのオブジェクトリテラル・コンストラクタ関数・クラスについて

JavaScriptのオブジェクトについてまとめました。

オブジェクトとは

オブジェクトとは、プロパティとメソッドが集まったもの。プロパティはオブジェクトのデータや属性といったものにあたり、メソッドはオブジェクトが行う処理のこと。

オブジェクトの作成方法の種類

JavaScriptでオブジェクトを作成する方法はオブジェクトリテラル、コンストラクタ関数、クラスを使う方法の3種類ある。

オブジェクトリテラル

オブジェクトリテラルで最も手軽にオブジェクトを作成できる方法で、{}を使って書く。コンストラクタ関数やクラスと異なり、引数に値を渡すといったことはできないので固定の値を持ったオブジェクトになる。

const person = {
    // プロパティ
    age: 10,

    // メソッド
    hello: function() {
        console.log('hello')
    }
}

{}によって作られたオブジェクトはJavaScriptのビルトインオブジェクトであるObjectインスタンス

ビルトインオブジェクトとは、JavaScriptにもともと定義されているオブジェクト。

Objectは全てのオブジェクトの元となるオブジェクト。

Objectnew演算子を使ってインスタンスを生成することもできるが、{}の方が簡潔に書けるため使う必要はない。

const obj = new Object()
console.log(obj) // {}

プロパティへのアクセス方法

プロパティにアクセスするにはドット記法とブラケット記法の2種類ある。

// ドット記法
console.log(person.age)

// ブラケット記法
console.log(person['age'])

存在しないプロパティにアクセスするとundefinedが返される。

console.log(person.name)

コンストラクタ関数

コンストラクタ関数は複数の似たオブジェクトを作成するための関数で、関数名は大文字から始める。

コンストラクタ関数を定義しただけではオブジェクトは作成されず、new演算子を使って実際にオブジェクトを作成する。

仮引数を作っておき、new演算子インスタンス化するときに引数に値を渡すことで、構造は同じだが値が異なるオブジェクトを作成できる。

function Person(name) {
    // プロパティ
    this.name = name
}

// インスタンスを作成
const takashi = new Person('takashi')
const hanako = new Person('hanako')

console.log(takashi) // Person {name: 'takashi'}
console.log(hanako) // Person {name: 'hanako'}

インスタンスメソッド・プロトタイプメソッド

コンストラクタ関数に直接記述した関数はインスタンスメソッドになる。

function Obj() {
    // インスタンスメソッド
    this.fn = function() {
        console.log('fn')
    }
}

インスタンスメソッドはインスタンスごとに作られるメソッド。そのためインスタンスの数だけメソッドが定義される。

インスタンス固有の動作やインスタンスの状態と処理が結びつく処理を書きたいときはインスタンスメソッドを使う。


一方、インスタンス間で共通の処理を実装したいときはプロトタイプメソッドを定義する。 プロトタイプメソッドはコンストラクタ関数のprototypeオブジェクトに記述する。

インスタンスメソッドはインスタンス化したオブジェクトそれぞれで定義されるが、プロトタイプメソッドはprototypeオブジェクトに定義されたメソッドへの参照を保持するので、1つだけ定義するだけで済む。

1つだけで済むということはそれだけメモリの消費が少なくなる。

イメージとしてはプロトタイプは親のオブジェクトであり、親のオブジェクトにメソッドを定義することで、子にあたるインスタンスで共通して親のメソッドを使えるということ。

function Person(age, name) {
    this.age = age
    this.name = name
}

// プロトタイプメソッド
Person.prototype.fn = function() {
    console.log('fn')
}

コンストラクタ関数はただの関数

コンストラクタ関数はnew演算子を使えばオブジェクトを生成できるというだけで、実際はただの関数。逆に言えば普通の関数もnew演算子を使えばコンストラクタ関数としてオブジェクトを作成できる。

// 関数宣言
function fn() {}

// 関数をnew演算子でインスタンス化
const obj = new fn()
console.log(obj) // fn {}

// コンストラクタ関数
function Fn() {
    console.log(this)
}

// コンストラクタ関数を関数として実行
Fn() // Window

コンストラクタ関数はオブジェクトを作るためのものだが、関数としてつかうこともできてしまうため、追加されたオブジェクトを作るための構文であるクラスを使ったほうが良い。

余談

コンストラクタ関数と似た用語にFunctionコンストラクタがあり、Functionコンストラクタと似た用語にFunctionオブジェクトがある。

Functionオブジェクト

Functionオブジェクトは組み込みのオブジェクトで、関数そのもの。関数宣言や関数式などで作られる関数は全てオブジェクト。

Functionコンストラク

FunctionコンストラクタはFunctionオブジェクトを作るための組み込みオブジェクト。

const obj = new Function('console.log(this)')
obj()

ただし非推奨なので関数式などを使って関数を作るのが普通。

クラス

class構文はES6から追加されたもので、コンストラクタ関数を書きやすくしたもの。

コンストラクタ同様、1文字目を大文字にする。

他の言語のクラスとは異なり、内部的にはプロトタイプで動いている。

class Person {
    constructor(age, name) {
        this.age = age
        this.name = name
    }

    hello() {
        console.log('hello')
    }

    // このメソッドの書き方はNG
    // hello: function() {}
}

const takashi = new Person('10', 'takashi')

コンストラクタ関数同様、new演算子を使ってインスタンス化する。

constructorはクラスが必ず持つ、インスタンス化したときに実行されるメソッド。

インスタンスメソッド・プロトタイプメソッド

constructor内に定義したメソッドがインスタンスメソッドになり、class直下に定義したメソッドがプロトタイプメソッドになる。

同じ名前のインスタンスメソッドとプロトタイプメソッドを定義しても上書きされずエラーにならない。インスタンスメソッドはプロトタイプメソッドより優先して実行される。

class Obj {
    constructor() {
        // インスタンスメソッド
        this.fn = function() {
            console.log('instance')
        }
    }

    // プロトタイプメソッド
    fn() {
        console.log('prototype') 
    }
}

const obj = new Obj()

// インスタンスメソッドがプロトタイプメソッドより優先的に呼ばれる
obj.fn() // instance

継承

継承する時はextendsを使う。継承することで、親のプロパティやメソッドを子で使用することができる。

// 親のクラスを定義
class Animal {
    constructor(name) {
        this.name = name
    }

    speak() {
        console.log(`${this.name}の鳴き声`)
    }
}

// 子のクラスを定義
class Dog extends Animal {}

// インスタンス化
const sibaken = new Dog('柴犬')

// 親のメソッドを使える
sibaken.speak() // 柴犬の鳴き声

親のメソッドを上書きする

子クラスで親のメソッドを上書きしたい時は子クラスで同じ名前のメソッドを定義する。

class Animal {
    constructor(name) {
        this.name = name
    }

    speak() {
        console.log(`${this.name}の鳴き声`)
    }
}

// 子のクラスを定義
class Dog extends Animal {
    // 親のメソッドを上書き
    speak() {
        console.log(`${this.name}が吠えた`);
    }
}

// インスタンス化
const sibaken = new Dog('柴犬')

// 親のメソッドを使える
sibaken.speak() // 柴犬が吠えた

親クラスのconstructorを子クラスでも実行する

親クラスのconstructorを子クラスでも使いたい時はsuperという特殊な変数を使う。

子クラスのconstructor内でsuperを使うことで子クラスをインスタンス化した時に親クラスのconstructorを呼び出せる。

class Parent {
    constructor(name) {
        this.name = name
        console.log('親のconstructor');
    }
}

// 子のクラスを定義
class Child extends Parent {
    constructor(name) {
        super(name)
        console.log('子のconstructor')
        console.log(this.name) // 子供
    }
}

// インスタンス化
const child = new Child('子供')

子クラスのconstructorsuperを記述しないとUncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructorが表示される。

また子クラスのconstructorsuperそれぞれの引数に親クラスのconstructorと同じ引数を指定しないまま子クラスでその引数を使おうとするとundefinedになる。

親クラスのメソッドを子クラスでも使う

superを使うことで親クラスのメソッドを子クラスでも使うことができる。

class Animal {
    constructor(name) {
        this.name = name
    }

    speak() {
        console.log(`${this.name}の鳴き声`)
    }
}

// 子のクラスを定義
class Dog extends Animal {
    // 親のメソッドを上書き
    speak() {
        // 親のメソッドをそのまま使う
        super.speak()
        console.log(`${this.name}が吠えた`);
    }
}

// インスタンス化
const sibaken = new Dog('柴犬')

// 親のメソッドを使える
sibaken.speak()

クラスは関数として呼び出せない

コンストラクタ関数と異なり、クラスは関数として呼び出すことはできない。

class Obj {}

Obj() // Uncaught TypeError: Class constructor Obj cannot be invoked without 'new'

まとめ

  • 1回限りのオブジェクトを作る時はオブジェクトリテラルを使う
  • 複数の似たオブジェクトを作成したいときはコンストラクタ関数やクラスを使う
  • 関数としても扱えてしまうコンストラクタ関数ではなく、オブジェクトを作るためのクラスを使うべき
  • クラスは内部的にはプロトタイプベースで動作する
  • インスタンスメソッドは個々のインスタンスごとに作られるメソッドで、プロトタイプメソッドはインスタンス間で共有するメソッド

JavaScriptの関数まとめ

JavaScriptの関数についてまとめました。

関数の種類

関数宣言

関数宣言はfunctionキーワードを使った、最もオーソドックスな関数。

// 関数の定義
function fn() {
    console.log('fn')
}

// 関数の実行
fn()

関数内でreturnを実行するとそれ以降の処理が行われない。returnを記述しない場合はその関数はundefinedを返す。

関数宣言は同じ関数を定義するとエラーではなく上書きされる。

function fn() {
    console.log('fn')
}

function fn() {
    console.log('上書き')
}

fn() // 上書き

意図せず上書きされることは避けたいので、関数はできるだけ関数式を使う。

関数式

関数式は関数を変数に代入したもの。JavaScriptにおける関数はオブジェクトなので値として変数に代入できる。

変数名が関数の呼び出し時の名前になる。

// 関数の定義
const fn = function() {
    // 処理
}

// 関数の実行
fn()

代入する関数には名前をつけることができるが意味はないので、基本的に名前をつけない。関数式に代入する名前がない関数を無名関数という。

関数式は関数が実行されるときに関数オブジェクトが作成されるため、定義する前に実行するとエラーになる。 定義する前に実行してみる。

// varに代入した場合
fn() // Uncaught TypeError: fn is not a function

var fn = function() {
    console.log('fn')
}
// letかconstに代入した場合
fn() // Uncaught ReferenceError: Cannot access 'fn' before initialization

const fn = function() {
    console.log('fn')
}

アロー関数

アロー関数はES6で追加された無名関数を省略して書ける関数。

// 基本的な書き方
const fn = () => {
    console.log('fn')
}

// 仮引数が1つのときは()を省略できる(仮引数がないときは()を省略できない)
const fn = name => {
    console.log(name + ' fn')
}

// 処理が1つの式の場合、{}とreturnを省略できる
const fn = () => console.log('fn')

アロー関数は自身にthisを持たず、外側のアロー関数を囲む関数のthisを参照する。

// グローバルスコープのアロー関数
const fn = () => {
    console.log(this)
}

fn() // Window(グローバルスコープのthis)

// メソッド内のアロー関数
const obj = {
    name: 'オブジェクト',
    method() {

        console.log(this.name) // オブジェクト

        const fn = () => {
            console.log(this.name) // オブジェクト(methodのthis)
        }

        fn()
    }
}

obj.method()

メソッドとして利用するとオブジェクトの参照ではなく、外側の関数やグローバルスコープのthisを参照する。

const obj = {
    name: 'オブジェクト',
    fn: () => {
        console.log(this.name) // undefined
        console.log(this) // Window
    }
}

obj.fn()

また、アロー関数は自身にargumentsを持たない。

const fn = () => {
    console.log(arguments) // Uncaught ReferenceError: arguments is not defined
}

fn()

new演算子を使ってコンストラクタとして使えず、prototypeプロパティを持たない

const Fn = (name) => {
    this.name = name
}

const obj = new Fn('オブジェクト')

console.log(obj.name) // Uncaught TypeError: Fn is not a constructor

これらの特徴からアロー関数はできることが限られているため、コードを書く人によっての差異が生まれにくい。

できるだけ無名関数を書くときはアロー関数を使う。

コールバック関数・高階関数

関数はオブジェクトであるため、関数の引数に渡すこともできる。引数として渡される関数をコールバック関数という。

コールバック関数を引数として使う関数を高階関数という。

function callbackFn() {
    console.log('callback')
}

function fn(callback) {
    callback()
}

fn(callbackFn)

fn高階関数で、関数callbackFnをコールバック関数として引数に受け取り、受け取ったコールバック関数を実行している。

コールバック関数は、非同期処理やイベントリスナー、配列のメソッドなどで使われる。

// 非同期処理
setTimeout(function() {
    // 1秒後に実行されるコールバック関数の処理
}, 1000);


// イベントリスナー
const btn = document.getElementById('button')

btn.addEventListener('click', function() {
    // ボタンがクリックされた時のコールバック関数の処理
})


// 配列のメソッド
const numbers = [1, 2, 3, 4, 5]

// mapメソッドは配列の要素1つずつに対して引数に与えられたコールバック関数を実行し、その結果を新しい配列として返すメソッド
const doubled = numbers.map(num => num * 2)

即時関数

即時関数は関数の定義と実行を同時に行う関数。関数スコープを作って、スコープの汚染を防ぐために使われる。

(function () {
    // この中で定義した変数はローカル変数になる
    var a = 'local'
    
    console.log(a) // local
})()

console.log(a) // Uncaught ReferenceError: a is not defined

function () {}を包んでいる()は算術の優先度を決めるためのもので、その後の()は関数の実行のためのもの。

普通の関数同様、引数を指定することもできる。

(function (a) {
    console.log(a) // local
})('local')

オブジェクトのメソッド

オブジェクトに定義した関数をメソッドという。

const obj = {
    fn() {
        console.log('fn')
    },

    // 関数宣言
    fn2: function() {
        console.log('fn2')
    },

    // アロー関数
    fn3: () => {
        console.log('fn3')
    }
}

obj.fn() // fn
obj.fn2() // fn2
obj.fn3() // fn3

引数

JavaScriptの関数は仮引数と実際に渡した引数の数が違っても実行できる。

渡した引数が足りない場合は仮引数にはundefinedが渡される。

function fn(a, b) {
    console.log(a) // fn
    console.log(b) // undefined
}

fn('fn')

渡した引数が多い時は、不必要な引数は無視される。

function fn(a) {
    console.log(a);
}

fn(0, 1) // 1は無視される

デフォルト引数

デフォルト引数は仮引数に値を指定しておくことで、実引数に値を指定しない場合でも勝手に値が指定されるようにするための引数。

function fn(a = 0) {
    console.log(a) // 0
}

fn()

arguments

argumentsは関数の中でのみ使える引数の全ての値が格納された変数。

配列のようにインデックスでアクセスできるが、配列のメソッドは使えない。

function fn() {
    console.log(arguments) // Arguments(4) ['a', 'r', 'g', 'u', callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log(arguments[0]) // a
    console.log(arguments[1]) // r
    console.log(arguments[2]) // g
    console.log(arguments[3]) // u
}

fn('a', 'r', 'g', 'u')

上記のように仮引数を指定したり、引数の数を固定しなくても、引数に与えられた値を参照できる。

しかしargumentsだと引数を受け取るのか、引数をどれだけ受け取るのかが明確ではなく、またアロー関数では使えないので、できれば可変長引数を受け取ることを明確にするRest parametersを使う。

Rest parameters

Rest parametersはES6で追加された仮引数に...をつけたもので、argumentsとは違い、可変長引数を受け取ることを明確にし、受け取った引数を配列として扱える。

function fn(...args) {
    console.log(args) // (9) ['a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's']
}

fn('a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's')

まとめ

  • 関数はできるだけ関数宣言ではなくアロー関数を使った関数式を使う
  • 関数にreturnを指定しないとundefinedを返す
  • コールバック関数は関数の引数として渡される関数
  • 即時関数はスコープの汚染を防ぐために使う
  • 可変長引数を受け取るときはできるだけargumentsではなくRest parametersを使う

JavaScriptの実行環境まとめ

JavaScriptがどのように実行されるかについてまとめました。

JavaScriptの実行環境

JavaScriptJavaScriptエンジンで実行される。

JavaScriptエンジンはJavaScriptのコードを解析してコンパイルし実行するプログラム。

JavaScriptエンジン上でECMAScriptやWebAPIs(ブラウザ上)が動作する。

V8というGoogleが提供しているオープンソースJavaScriptエンジンのシェアが多い。

JavaScriptのコードがどのように実行されるか

コードの実行前

JavaScriptエンジン上でJavaScriptのコードが動作する。それに加えてコードの実行前にはグローバルオブジェクトとthisが用意される。

グローバルオブジェクトは実行環境によって異なり、ブラウザ上ではWindowオブジェクトとなり、その中にWebAPIsが含まれる。

実行コンテキスト

実行コンテキストとはコードが実行されている状況のこと。コードが実行されている状態によってコンテキストは変化する。

実行コンテキストにはグローバルコンテキスト、関数コンテキスト、evalコンテキストの3つの種類がある。evalコンテキストは非推奨なので、重要なのはグローバルコンテキストと関数コンテキスト。

グローバルコンテキスト

グローバルコンテキストでは以下の3つが使える。

  • 実行中のコンテキスト内の変数や関数
  • グローバルオブジェクト
  • this

グローバルコンテキストでの実行中のコンテキスト内の変数や関数はグローバルスコープにあたる。

thisは実行コンテキストによって参照先のオブジェクトが変わる変数のようなもの。

関数コンテキスト

関数コンテキストは関数が実行されているときのコンテキストで、以下の5つが使える。

  • 実行中のコンテキスト内の変数や関数
  • arguments
  • super
  • this
  • 外部変数

関数コンテキスト内での実行中のコンテキスト内の変数や関数は関数スコープにあたる。

argumentsは関数に与えられた引数がすべて格納された、関数の中でのみ参照できる特殊な変数。

superは継承元の関数を呼び出す特殊なキーワード。

外部変数は外側のスコープにある変数のこと。

コールスタック

コールスタックは、コードがどの順番で実行されたかの履歴を表すようなもの。

コールスタックの中に新しく作成されたコンテキストが積まれていき、実行中のコンテキストが一番上にくる。実行が完了したコンテキストから消滅していき、最終的にはコールスタックの中身は空になる。

具体的には、最初に必ずグローバルコンテキストが作られ、コードが上から順番に実行されていく。その途中で関数があれば関数コンテキストが作られる。

function a() {
    
}

function b() {
    a()
}

function c() {
   b() 
}

c()

上記のコードは以下のような順番でコールスタックが積まれて消滅する。

  1. 最初にグローバルコンテキストが作られる
  2. コードが上から読まれてcの関数が実行され、cの関数コンテキストが作られる
  3. cの中で実行されたbの関数コンテキストが作られる
  4. bの中で実行されたaの関数コンテキストが作られる
  5. aの実行が完了してaの関数コンテキストが消滅する
  6. bの実行が完了してbの関数コンテキストが消滅する
  7. cの実行が完了してcの関数コンテキストが消滅する

このように後入れ先出しの仕組みになっている。

まとめ

  • JavaScriptJavaScriptエンジンで実行される
  • JavaScriptのコードを実行する前にグローバルオブジェクトとthisが用意される
  • JavaScriptのコードが実行されるとグローバルコンテキストが作られ、関数が実行されると関数コンテキストが作られる
  • コールスタックにコンテキストが後入先出しの仕組みで積まれていく

jsprimerで学んだJavaScriptの基礎まとめ

JavaScriptの基礎を学ぶためにjsprimerという無料の教材を読んで写経しました。

感想

内容は2部構成になっていて、1部でJavaScriptの基礎文法を学び、2部でサンプルのアプリを作成します。

無料ですが文法をしっかり学んだ上でアプリを作ることもできるので、Progateなどをやった後やReact、Vueなどのフレームワークをやる前のJavaScriptの言語仕様を学ぶに最適だと思います。

1部はRubyを学んでいたので、共通するような文法は流し読みでいけたのですが、クロージャーやthis、非同期処理などの理解が特に難しかったです。

いろんな関数が出てくるので、関数の理解が特に重要だなと感じました。

2部では非同期処理を使ってGithubAPIからユーザー情報を取得できるアプリ、Node.jsを使ってMarkdownをHTMLに変換するCLIアプリ、Todoアプリを作りました。

それぞれのコードの説明もされていて、動くコードを書いてからリファクタリングしていくやり方なので基本的にはわかりやすかったのですが、それでもTodoアプリのクラスや関数のつながりや処理の流れを追うのは大変でした。

静的解析ツール、テストなどの周辺のツールについての解説はないので、そこらへんは自分で調べる必要があります。

さっさとJavaScriptの基礎は理解して、Reactの勉強に入ろうと思います。

新しく学んだこと

新しく学んだ重要そうな部分をまとめておきます。

第一部

JavaScriptとは

  • ブラウザだけでなくNode.jsというサーバー側のアプリを作る仕組みでも利用される
  • JavaScriptECMAScriptというどの実行環境でも共通で動作する仕様と、実行環境によって異なる固有の機能で成り立つ
  • JavaScriptは大部分がオブジェクト
  • 開発者が安全にコードを書けるように、strict modeという古く安全でない構文や機能の一部が禁止される実行モードが存在する
  • デフォルトの実行コンテキストであるScriptと、ES2015で導入されたJavaScriptをモジュールとして実行するための実行コンテキストであるModuleがある
  • Scriptはデフォルトでstrict modeではなく、Moduleはデフォルトでstrict mode

コメント

  • //は1行のコメント
  • /* */は複数行のコメント

変数と宣言

  • 変数を宣言するキーワードにはvarletconstがある
  • varは古いキーワードで意図しない動作を作りやすい
  • letconstvarの問題を改善するためにES2015で追加された
  • letは再代入ができ、初期値を指定しない変数も定義できる
  • 初期値を指定しない場合はundefinedという値が未定義であることを表す値になる
  • constは再代入ができない
  • varの問題点
    • 同じ名前の変数を再定義できてしまう
    • 変数の巻き上げ
  • constは初期化した後でも値を変更できるオブジェクトにも使えるので定数ではない

値の評価と表示

  • JavaScriptの多くの実行環境では、ConsoleAPIを使ってコンソールに表示する
  • console.logデバッグとして使える
  • エラーには構文エラーと実行時エラー(ランタイムエラー)の2種類ある
  • 実行時エラーは実行するまでエラーになるかわからないので、エラーの原因を探るデバッグを行う必要がある

データ型とリテラル

  • JavaScriptのデータ型にはプリミティブ型(基本型)とオブジェクトの2つに分類される
  • プリミティブ型は一度作成したらその値自体を変更できないイミュータブルという特性を持つ
  • オブジェクト型は一度作成した後もその値自体を変更できるミュータブルという特性を持つ
  • プリミティブ型は7つある
    • 真偽値
    • 数値
    • 巨大な整数
    • 文字列
    • undefined
    • null
    • シンボル
  • プリミティブ型ではないものオブジェクト型になる
  • データ型の値を直接記述できるように構文として定義されたものがリテラル
  • undefinedはリテラルではなくただのグローバル変数undefinedという値を持っているだけ
  • オブジェクトリテラル{}で新しいオブジェクト作成できる
  • プリミティブ型のデータでもオブジェクトのように参照できる仕組みがあるため、ラッパーオブジェクトを明示的に使う必要はない

演算子

  • 任意の数値を0で除算した結果は、無限大を表す数値であるInfinityとなる
  • NaNNot-a-Numberの略称で、数値ではないがNumber型の値になる
  • ===は同じ型で同じ値である場合にtrueを返す、オブジェクトの場合は参照が同じである場合にtrueを返す
  • ==は同じ型で同じ値である場合にtrueを返すが、異なる型の値であった場合、同じ型になるように暗黙的な型変換をしてから比較するので、意図しない挙動が発生する可能性がある
  • 例外的にnullundefinedの比較のために==が使われることがある
  • 配列やオブジェクトの値を複数の変数に同時に代入できるのが分割代入
  • 暗黙的にfalseに変換される値
    • false
    • undefined
    • null
    • 0
    • 0n
    • NaN
    • ""
  • AND演算子で左辺がfalseの場合、右辺は評価されない、このことを短絡評価という
  • OR演算子は左辺がtrueの場合、右辺は評価されない
  • 評価結果がnullまたはundefinedとなる値をnullishという
  • カンマで区切った式は左から順に評価される

暗黙的な型変換

  • 暗黙的な型変換はバグの原因となるので、型変換をしたい場合は明示的にする
  • Booleanコンストラクタで真偽値に変換できる
  • Stringコンストラクタで数値から文字列に変換できる
  • シンボルは暗黙的な型変換ができない
  • Numberコンストラクタで文字列から数値に変換できる
  • NaNは何と演算してもNaNになり、デバッグが難しくなるので避けるべき

関数と宣言

  • returnの値を省略、またはreturnそのものを省略した場合はundefinedが返される
  • 仮引数と呼び出し時の引数の数が違っても関数を呼び出せる
  • 呼び出し時の引数が少ない場合、余った仮引数にはundefinedが代入される
  • ES2015からはデフォルトで引数を代入できるデフォルト引数を指定できる
  • 呼び出し時の引数が多い場合は、溢れた引数は無視される
  • 引数が固定ではなく、任意の個数の引数を受け取るものを可変長引数という
  • 可変長引数を実現するには、Rest parametersargumentsを使う
  • ES2015から追加されたRest parametersは関数に渡された値が配列として代入される可変長引数
  • argumentsは関数の中でのみ参照できる特殊な変数で、渡された引数の値が全て入っている配列のようなオブジェクト
  • Rest parametesを使えるならargumentsは使わない
  • 関数はオブジェクトの一種で、()をつけると処理を呼び出せて、()をつけないとオブジェクトとして参照できる
  • 関数をあたいとして変数へ代入したものを関数式という
  • 関数宣言は文で、関数式は値として扱う
  • 関数式で名前を持たない関数を代入したものを無名関数という
  • ES2015では無名関数を=>を使ってArrow Funtionで書ける
  • thisの挙動やargumentsを使えないなどの解釈や実装による違いが生まれにくい特徴から、基本的にはArrow Functionを使い、そうでない場合はFunctionを使う
  • 関数の引数として渡された関数をコールバック関数という
  • コールバック関数はいちいち定義するのは面倒なので、無名関数として使うことが多い
  • コールバック関数を引数として使う関数を高階関数という
  • コールバック関数は非同期処理でよく使われる

文と式

  • JavaScriptは文と式から構成される
  • 式は値を生成し、変数に代入できるもの
  • 文は処理する1ステップのことで、変数に代入できない
  • {}で囲んだ部分をブロックという
  • if文などと組み合わせずに単独のブロック文を書くことはほとんどない

条件分岐

  • 1行のif文はブロックを省略できるがわかりづらいので常にブロックで囲むことが推奨される
  • switch文の式は===で評価される
  • switch文はif文の代用より、関数と組み合わせて条件に対する値を返すパターンとして使われることが多い

ループと反復処理

  • while文は他により安全な反復処理の書き方があるので、使う場面は限られる
  • do-while文は条件がfalseでも最初に処理が実行される
  • 配列のforEachメソッドは条件式がなく、配列の全ての要素を反復処理する
  • for...in文はオブジェクトのプロパティに対して反復処理を行う
  • for...in文は親オブジェクトのプロパティまで列挙可能なものを探すので、意図しない結果になる場合がある
  • ES2015で追加されたfor...of文は反復処理時の動作が定義されたオブジェクトの総称であるiterableオブジェクトを反復処理できる
  • Array、String、Map、Setなどはiterableオブジェクト
  • for文などの構文はcontinue文やbreak文を使える
  • 配列のメソッドでは一時的な変数が必要なかったり、処理をコールバック関数として書く

オブジェクト

  • JavaScriptではObjectというどの実行環境でも使えるビルトインオブジェクトが定義されている
  • {}Objectインスタンスオブジェクトになる
  • new演算子でもインスタンスを作成できるが、簡潔な{}を使うべき
  • プロパティの参照では基本的に.を使い、変数を指定したい場合は[]を使う
  • オブジェクトはミュータブルの特性を持つ
  • オブジェクトの初期化時以外にプロパティを追加するとどんなプロパティを持つか分かりにくくなるので、オブジェクト作成時に定義する
  • 存在しないプロパティにアクセスすると、例外ではなくundefinedが返される
  • プロパティの存在を確認するにはin演算子か、Object.hasOwn静的メソッドを使う
  • オブジェクトのプロパティにアクセスするとプロパティ名は暗黙的に文字列に変換される
  • Object.assingメソッドを使うと、オブジェクトのマージや複製ができる

プロトタイプオブジェクト

  • オブジェクトに組み込まれたメソッドをビルトインメソッドという
  • ほとんどすべてのオブジェクトはObject.prototypeプロパティに定義されたprototoypeオブジェクトを継承している
  • prototypeはすべてのオブジェクトの作成時に自動的に追加される、すべてのオブジェクトから利用できるメソッドなどを提供する特殊なオブジェクト
  • prototypeオブジェクトに組み込まれているメソッドをプロトタイプメソッドという
  • インスタンスからプロトタイプメソッドを呼び出せることをプロトタイプチェーンという
  • 同じ名前のプロトタイプメソッドとインスタンスメソッドはインスタンスメソッドが優先して呼び出される
  • ArrayArray.prototypeをもつ
  • Object.create(null)でプロトタイプオブジェクトを継承しない完全に空のオブジェクトを作れる

配列

  • JavaScriptにおける配列は可変長
  • 存在しないインデックスに対してアクセスするとundefinedを返す
  • 配列には未定義の値を持つ要素を含むことができる
  • 配列から要素を検索する目的
    • インデックスを取得する
    • 要素自体を取得する
    • 要素が存在するかの真偽値を取得する
  • 配列の要素の追加、削除
    • 末尾に追加 - push
    • 末尾を削除 - pop
    • 先頭に追加 - unshift
    • 先頭を削除 - shift
    • 任意のインデックスの要素を削除 - Array.prototype.slice
  • ES2015で追加されたSpread構文を使うことで、配列の中に既存の配列を展開できる
  • 破壊的なメソッドは配列オブジェクトそのものを変更し、非破壊的なメソッドは配列オブジェクトのコピーを作成してから変更する
  • 反復処理の中でよく使われるメソッド
    • forEach - 反復処理
    • map - 反復処理を行なって新しい配列を返す
    • filter - 反復処理を行いtrueを返した要素だけの新しい配列を返す
    • reduce - 反復処理を行い、累積値を返す(可読性がよくない)
  • 配列のメソッドはメソッドチェーンといって繋げて実行でき、複数の処理をまとめることができる

文字列

  • JavaScript文字コードUnicodeを採用し、文字をエンコードする方式としてUTF-16を採用している
  • UTF-16はそれぞれの文字を16ビットのビット列に変換するエンコード方式
  • 1文字を表すのに使う最小限のビットの組み合わせをCode Unitという
  • つまり、JavaScriptにおける文字列は16ビットのCode Unitが順番に並んだものとして内部的に管理されている
  • 文字列の厳密比較は以下の条件を満たしていれば同じ文字列となる
    • Code Unitが同じ順番で並んでいるか
    • 文字列の長さが同じか
  • 正規表現リテラルソースコードをパースした段階で評価され、RegExpコンストラクタは通常の関数と同じように呼び出した時に評価される
  • 正規表現リテラルの方が簡潔でパフォーマンスがいいが、変数を使いたい時などはRegExpコンストラクタを使う
  • URLなどの構造的な文字列を扱う場合は専用の関数を使うべき

文字列とUnicode

  • UTF-16を採用するのはJavaScriptの内部であり、ファイルの文字コードは他の文字コードでも問題ない
  • Unicodeにおける文字に対する一意のIDをCode Pointという
  • Code UnitやCode Pointを意識しなくても文字列の処理はできるが、絵文字を使うときはCode Pointを意識する必要がある

ラッパーオブジェクト

  • 真偽値、数値、BigInt、文字列、シンボルにはそれぞれ対応するオブジェクトがあり、それらをラッパーオブジェクトという
  • プリミティブ型の値に対してプロパティアクセスする時、自動で対応するラッパーオブジェクトに変換される
  • ラッパーオブジェクトではなくリテラルを使うべき
  • JavaScriptは全てがオブジェクトであるわけではなく、すべてがオブジェクトのように見えるというのが正しい

関数とスコープ

  • 関数は変数や関数の引数などを参照できる範囲であるスコープを持つ
  • スコープの中で定義された変数はスコープの外からは参照できない
  • 関数の仮引数はスコープに紐づけられる
  • 関数によるスコープを関数スコープという
  • {}で囲まれた範囲をブロックスコープという
  • for文はループごとに新しいブロックスコープを作成した
  • スコープはネストでき、内側のスコープから外側のスコープにある変数は参照できる
  • 内側から外側のスコープへ順番に変数を探すことをスコープチェーンという
  • もっとも外側のスコープをグローバルスコープといい、グローバルスコープにある変数をグローバル変数という
  • むやみにグローバル変数を定義しない
  • 変数を参照できる範囲をできるだけ小さくする
  • letは変数を宣言する前に参照するとエラーになるが、varundefinedになるのでエラーにならない → 変数の巻き上げ
  • varブロックスコープを無視する
  • functionキーワードを使った関数宣言も宣言より前に呼び出せる巻き上げが起こる
  • letconstが追加されるまでは、関数スコープを作ってグローバルスコープの汚染を避けるために即時実行関数を使われていた
  • どの識別子がどの変数を参照しているかを静的に決定する性質を静的スコープといい、JavaScriptの変数や関数の参照先は静的スコープで決まる
  • JavaScriptには参照されなくなった不要なデータをメモリから解放するガベージコレクションという仕組みがある
  • 静的スコープとメモリ管理の仕組みによって、関数内から特定の変数を参照し続けることで関数が状態を持てる仕組みのことをクロージャーという
  • 関数はオブジェクトであるためプロパティに状態を持たせることもできるが、関数の外からプロパティを変更できるため推奨されない
  • クロージャーはグローバルスコープの汚染を防いだり、関数に状態を持たせるために使う

関数とthis

  • thisは読み取り専用のグローバル変数のようなもので、条件によって参照先が異なる
  • thisが実際に使われるのはメソッドで、メソッド以外では使うべきではない
  • 実行コンテキストにおけるthis
    • 最も外側のスコープでは実行コンテキストによってthisの参照先は変わるので、使うべきではない
    • スクリプトにおけるthisの参照先 → グローバルオブジェクト(実行環境ごとに異なる)
    • モジュールにおけるthisの参照先 → undefined
  • 関数とメソッドにおけるthis
    • Arrow Function以外の関数におけるthis
      • 関数宣言、関数式におけるthisの参照先 → undefined
      • メソッド呼び出しにおけるthisの参照先 → ベースオブジェクト
    • strict modeではないとthisundefinedの場合、グローバルオブジェクトを参照するように変換されてしまう
    • Arrow Functionにおけるthis
      • Arrow Functionはthisをもてない
      • 参照先 → 外側のスコープのthis
  • thisは定義したときではなく実行時に決定されるので、関数にthisが含まれていると意図しない結果が発生する場合がある
    • 対策
      • メソッドは関数ではなくメソッドとして呼ぶ
      • callapplybindメソッドを使って明示的にthisを指定する
  • 明示的にthisを指定することで、本来undefinedとなる部分にオブジェクトを渡すことができる
  • callapplyの違いは引数への値の渡し方が異なる
  • bindthisが束縛された関数を作る
  • コールバック関数はただの関数として呼ばれベースオブジェクトがないので、thisundefinedになる
    • 対策
      • thisthatのような一時変数に代入する
      • Arrow Functionでコールバック関数を使う(ES2015からはこっちの方が簡潔)

クラス

  • JavaScriptではES2015まではクラスがなく関数を使ってクラスのようなものを表現していた → 書き方を統一するためにES2015でclass構文が導入される
  • class構文はプロトタイプベースの継承の仕組みを使って関数でクラスを表現している
  • クラスは必ずコンストラクタを持つ
  • クラスは関数式のように値として定義できる
  • コンストラクタ内でのthisインスタンスのオブジェクトを参照する
  • new演算子インスタンスが返されることが期待されるため、コンストラクタでreturn文を使って任意のオブジェクトを返すべきではない
  • 関数で表現したクラスは関数として呼び出せるが、class構文で定義したクラスは関数として呼び出すことはできない
  • インスタンス間で共有されるメソッドをプロトタイプメソッドという
  • 外から読み書きして欲しくないプロパティには_をつける慣習がある
  • 外からアクセスできるプロパティをPublicクラスフィールド、外からアクセスできないプロパティをPrivateクラスフィールド
  • 静的メソッドにはstaticをつける
  • 静的メソッド内のthisはクラス自身を参照する
  • プロトタイプメソッドはプロトタイプオブジェクトに、インスタンスオブジェクトのメソッドはインスタンスオブジェクトに定義されるので、同時に定義しても上書きされない
  • インスタンスオブジェクトのメソッドがプロトタイプメソッドより優先して呼び出される
  • classも関数オブジェクトの1種であるため、自動的にprototypeプロパティにプロトタイプオブジェクトが作成される
  • class構文のメソッド定義はプロトタイプオブジェクトのプロパティとして定義される
  • インスタンスにメソッドを定義していなくても、インスタンスの生成時にクラスのプロトタイプオブジェクトへの参照が保存されるので、プロトタイプチェーンによってインスタンスからクラスのプロトタイプメソッドを呼び出せる
  • インスタンスはどのクラスから作られたかと、そのプロトタイプオブジェクトを知っている
  • オブジェクトがプロパティを探す時は、まずインスタンス自身から探し、次に[[Prototype]]の参照先を探し、どこにも無かったらundefinedを返す
  • super()で子クラスから親クラスのconstructorを呼び出せる
  • コンストラクタは親クラスから実行される
  • ビルトインオブジェクトも継承できる

例外処理

  • tryの中で例外が発生するとcatchの処理が実行される
  • finallyの処理は必ずtryの最後に実行される
  • throwで例外を投げることができる
  • デバッグに役立つスタックトレースを得るために、例外はErrorオブジェクトのインスタンスを投げるべき
  • ビルトインエラーの種類
    • ReferenceError - 存在しない変数や関数が参照された時のエラー
    • SyntaxError - 構文エラー
    • TypeError - 値が期待される型ではない場合のエラー
  • エラーに関するログ出力はconsole.errorを使う

非同期処理:Promise/Async Function

  • コードをを順番に1つずつ実行する処理を同期処理という
  • 同期処理では現在の処理が終わるまで次の処理に進めない
  • JavaScriptの処理はブラウザのメインスレッドで実行される
  • メインスレッドはUIに関する処理も行われるため、他の処理が実行されると表示が更新されなくなる
  • 同期処理とは反対に処理の終了を待たずに次の処理を実行するものを非同期処理という
  • 非同期処理も大部分はメインスレッドで実行される
  • 非同期処理は処理を一定の単位ごとに分けて切り替えながら実行する並行処理として扱われる
  • 実行環境によってメインスレッドとは別のスレッドで実行できるものもある
  • 非同期処理では例外をキャッチできない
  • 非同意処理の外からは非同期処理の中で例外が発生したかわからないため、例外が発生したことを非同期処理の中から外に伝える方法が必要
Promise
  • PromiseはES2015で導入された非同期処理の状態や結果を表現するビルトインオブジェクト
  • 非同期処理が成功すればresolve()を呼び、失敗すればreject()を呼び出す
  • 成功時のコールバック関数はthenメソッドで登録し、失敗時のエラー処理はthenではなくcatchメソッドを使う
  • Promiseではコンストラクタの処理で例外が発生した場合には自動的に例外がキャッチされ、thencatchで登録したエラー時のコールバック関数が呼び出される
  • Promiseのインスタンスには3つの状態がある
    • Fulfilled - 成功
    • Rejected - 失敗または例外発生
    • Pending - インスタンスを作成した時の初期状態
  • 複数の非同期処理を順番に扱いたい場合はPromiseをメソッドチェーンでつなぐPromiseチェーンを使う
  • 成功時、失敗時のどちらの場合でも呼び出したい処理はfinallyメソッドに書く
Async Function
  • Async FunctionはES2017で追加された非同期処理を行う関数を定義する構文で、Promiseの上に作られている
  • Async Functionは関数の前にasyncをつけ、必ずPromiseインスタンスを返す
  • awaitを使うことで、Promiseチェーンの可読性を解決し、非同期処理を同期処理のように扱える
  • awaitは右辺のPromiseインスタンスがFulfilledまたはRejectedになるまで非同期処理の完了を待ち、Promiseの状態が変わると次の行の処理を再開する
  • awaitはPromiseがRejectedになった場合に例外をキャッチする
  • awaitはAsync Functionの直下でのみ使える

Map/Set

  • MapとSetはES2015で追加されたデータの集まりであるコレクションを扱うビルトインオブジェクト
Map
  • Mapはキーと値の組み合わせであるマップを扱うためのビルトインオブジェクト
  • newで新しいMapオブジェクトを作成する
  • コンストラクタにキーと値の配列を初期値として渡すことができる
  • ObjectをMapとして使うメリット
    • リテラル表現があるため作成しやすい
    • JSONに変換しやすい
    • APIやライブラリなどの関数がマップとしてObjectが渡される設計になっている
  • Mapを使うメリット
    • プロトタイプのメソッドやプロパティとキーが衝突しない
    • キーにはあらゆるオブジェクトを使える
    • マップのサイズを簡単に知ることができる
    • 要素を簡単に列挙できる
Set
  • Setは重複する値がないことを保証したコレクション
  • 要素は順序とインデックスを持たない
  • newで新しいSetオブジェクトを作成する
  • 重複する値は無視される

JSON

  • JSONはオブジェクトリテラル、配列リテラル、各種プリミティブ型の値を組み合わせたもの
  • JSONではオブジェクトのキーを必ずダブルクォートで囲まなければならない
  • JSON.parseメソッドで、JSONの文字列をオブジェクトに変換できる
  • 実際のアプリでJSONを扱うのは外部のプログラムとデータを交換する用途がほとんど
  • 外部のプログラムが送ってくるデータが常にJSONとは限らないため、常に例外処理をすべき
  • JSON.stringifyメソッドで、オブジェクトをJSONの文字列に変換できる

Date

  • Dateオブジェクトは常にnew演算子を使ってインスタンスを作成する
  • Dateでは機能が不十分なので、ライブラリを使うことが一般的

Math

  • Mathオブジェクトは数学的な定数と関数を提供するビルトインオブジェクト
  • コンストラクタではないため、インスタンスを作らずに静的なプロパティやメソッドとして提供する

ECMAScriptモジュール

  • モジュールとは変数や関数などをまとめたJavaScriptの1ファイル
  • モジュールは依存性の高いコードをまとめて、再利用するために使う
  • モジュールを外部から使えるようにすることをエクスポート、モジュールを読み込むことをインポートという
  • エクスポート・インポートそれぞれに名前付きとデフォルトの2種類ある
  • 名前付きにはエイリアスを使って違う名前でエクスポート/インポートできる
  • デフォルトエクスポートはモジュールごとに1つしかエクスポートできない特殊なエクスポート
  • 関数は宣言と同時にエクスポートできるが、変数はできない
  • デフォルトインポートはデフォルトエクスポートに名前をつけてインポートする
  • import * asで全ての名前付きエクスポートをまとめてインポートでき、モジュールごとの名前空間となるオブジェクトを宣言し、そのプロパティを使ってアクセスする
    • ファイルをモジュールとして読み込むにはscriptタグのtype属性をmoduleとする(指定しない場合構文エラーとなる)

第二部 応用編

  • Node.jsはJavaScript実行環境のひとつで、V8JavaScriptエンジンで動作する
  • Node.jsにはnpmというパッケージマネージャーが同梱されている
  • npmコマンドではなく、npxコマンドを使うとnpmで公開されている実行可能なパッケージのインストールと実行をまとめてできる

Ajax

  • HTMLのコンテンツと構造をJavaScriptから操作できるオブジェクトをDOMといい、動的なWebアプリを作るためには不可欠
  • DOMはブラウザが実装しているAPIで、HTMLをブラウザで読み込む時に生成され、HTMLのタグと入れ子構造を木構造で表現する
  • Fetch APIを使うことで、ページを再読み込みすることなくHTTP通信を行い指定したURLからデータを取得できる
    • fetchメソッドでリクエストを送信でき、Promiseを返す
    • 返されたPromiseインスタンスはレスポンスを表すResponseオブジェクトでresolveされる
    • response.statusでHTTPのステータスコードを取得できる
    • Fetch APIが標準化される前はXMLHttpRequestが使われていた
  • JavaScriptでHTML要素をDOMに追加する方法は2つある
    • HTML文字列をinnerHTMLプロパティにセットする
    • Elementオブジェクトを生成して手続き的にツリー構造を構築する
  • HTMLのエスケープはライブラリで行うのが一般的
  • バッククォートの前に関数を書くとタグ関数として呼び出せる

Node.jsでCLIアプリ

  • Node.js環境ではconsole.logの出力先は標準出力になる
  • JavaScriptのコードをNode.jsで実行するにはnodeコマンドを使う
  • Node.jsではエントリーポイントとなるJavaScriptファイルを作成し、そのファイルをnodeコマンドの引数に渡して実行するのが基本
  • Node.jsのグローバルオブジェクトはglobalオブジェクト
  • Node.jsの実行プロセスの情報の取得と操作ができるprocessargvというグローバル変数のプロパティによってコマンドラインの引数にアクセスできる
  • アプリでコマンドライン引数を扱うときは一度パースして扱いやすい値に整形するのが一般的
  • ECMAScriptモジュールの前はCommonJSモジュールが使われていて、相互運用性に注意する
  • Node.jsでファイルの読み書きを行うにはfsモジュールを使う

Todoアプリ

  • JavaScriptから扱うid属性は慣習的にjs-からはじめる名前にする
  • イベントの発生を元に処理を進めることをイベント駆動(イベントドリブン)という
  • 直接DOMを更新する問題
    • 状態をすべてHTMLに埋め込み、文字列として扱わなければならない
    • 更新箇所が増えると操作に対する処理が複雑になる
  • 直接DOMを更新する問題を解決するにはモデルを使って状態を管理する
  • 表示は操作ではなくモデルが変化したタイミングで更新する
  • 状態が変化したらイベントを発生させる
  • イベントはディスパッチとリスナーによって成り立つ

開発を補助するツール

  • Babelは古いブラウザにも対応させるために、新しい構文を古い構文に変換するツール
  • TypeScriptはJavaScriptに静的型づけの構文を追加した言語
  • モジュールバンドラーはJavaScriptのモジュール依存関係を解決し、複数のモジュールを1つのJavaScriptファイルに結合するツールで、webpackがよく使われる

JavaScriptのスコープの違い

JavaScriptのスコープについてまとめました。

スコープとは

スコープとは、実行中のコードから変数や関数などの値と式が参照できる範囲のこと。スコープの内側では参照ができ、スコープの外からスコープに定義されている変数は参照できない。

異なるスコープなら同じ変数名や関数名を定義できる。

スコープの種類

グローバルスコープ

グローバルスコープはプログラム実行時に暗黙的に作られる一番外側のスコープで、グローバルスコープに定義された変数はプログラムのどこからでも参照できる。

const a = 'global'

function fn() {
    
    function fn2() {

        function fn3() {
            // 関数の中の関数の中の関数の中からでも参照できる
            console.log(a) // global
        }

        fn3()
    }

    fn2()
}

fn()

関数スコープ

関数スコープは関数内に作られるスコープ。

function fn() {
    // 関数スコープ
    var a = 0
    let b = 0
    const c = 0
}

// 関数の外から参照するとエラーになる
console.log(a) // Uncaught ReferenceError: a is not defined
console.log(b) // Uncaught ReferenceError: b is not defined
console.log(c) // Uncaught ReferenceError: c is not defined


関数内で定義した関数を外からは参照できない、

function fn() {
    console.log('fn')

    function fn2() {
        console.log('fn2')
    }
}

fn() // fn
fn2() // Uncaught ReferenceError: fn2 is not defined

関数スコープ内に変数を定義することによってグローバルスコープの汚染を防ぐことができるので、関数内でしか使わない変数は関数内に定義する。

ブロックスコープ

ブロックスコープは{}の中のスコープで、if文やwhile文もブロックスコープにあたる。

ブロックスコープ内でvarを使って定義した変数は外から参照できてしまうので、letもしくはconstを使うようにする。

{
    // ブロックスコープ
    var a = 0
    let b = 1
    const c = 2
}

// varで定義した変数は参照できてしまう
console.log(a) // 0

// let、もしくはconstで定義した変数は外から参照できない
console.log(b) // Uncaught ReferenceError: b is not defined
console.log(c) // Uncaught ReferenceError: c is not defined

ブロックスコープ内の関数宣言は外から参照でき、letconstを使った関数式は参照できない。

{
    // 関数宣言
    function fn() {
        console.log('fn')
    }

    // 関数式
    const fn2 = function() {
        console.log('fn2')
    }
}

fn() // fn
fn2() // Uncaught ReferenceError: fn2 is not defined

レキシカルスコープ

レキシカルスコープは、コードを書く場所によって参照できる変数が変わるスコープのこと。実行中のコードから見た外部スコープを指す。

コードが実行されるタイミングではなく、コードを記述したタイミングでスコープが決定される。

変数aを参照する関数fn2を関数fnの中に記述すると参照できる。

function fn() {
    const a = 0

    function fn2() {
        // 外側のスコープに定義されているので参照できる
        console.log(a) // 0
    }

    fn2()
}

fn()

しかし、関数fn2をグローバルスコープで定義して実行するとエラーになる。

function fn() {
    const a = 0
}

fn()

function fn2() {
    // aは別の関数スコープの中に定義されているため参照できない
    console.log(a) // Uncaught ReferenceError: a is not defined
}

fn2()

このようにコードを記述する場所が変わることで参照できる変数も変化する。

また、レキシカルスコープは関数を実行した時点ではなく、定義した時点でスコープが決まる。

const a = 0

function fn() {
    console.log(a) // 0
}

function fn2() {
    const a = 1

    // fnを定義した時点で0を参照しているので、1にならない
    fn()
}

fn()
fn2()

スコープチェーン

スコープチェーンとは、内側のスコープから一番近い外側へのスコープへと順番に参照できる変数を探す仕組みのこと。

別のスコープで同じ名前の変数が定義されている場合は、内側から優先して参照される。

// グローバルスコープ
const a = 'global'

// ブロックスコープ
{
    const a = 'block'

    // 一番近いblockを参照
    console.log(a) // block

    // 関数スコープ
    function fn() {
        const a = 'function'

        // 一番近いfunctionを参照
        console.log(a) // function
    }

    fn()

    // 関数スコープは無視して一番近いblockを参照
    console.log(a) // block
}

// ブロックスコープは無視して一番近いglobalを参照
console.log(a) // global

まとめ

  • グローバルスコープにはなるべく変数を定義しない
  • 内側のスコープから一番近い外側のスコープから順番に参照できる変数を探していき、なければ未定義のエラーを返す