はじめてのJavaScript
2019 T.Takeda
知っておくべきいくつかのこと
正確には、ECMAScriptという標準のMozilla実装
- スクリプト言語
- 動的型付け言語、弱い型付け
- プロトタイプベースのオブジェクト指向
- プロトタイプチェーン
- スコープチェーン
- クロージャー
スクリプト言語
- コンパイルしないため、一般的に実行速度が遅い
- 動かすまで何が起こるかわからない怖さ
弱い型付け、動的型付け言語
実行時に型が決定される言語
- ダックタイピング
- いつの間にか数値が文字列になったりする
- プログラミング初心者には使いやすいが品質担保が難しいことを理解する
💡ダックタイピング・・型ではなく振るまいとして動作を期待する方式
💡静的型付けかつ型推論を持つクラスベースのTypeScriptをマイクロソフトが開発したのはなぜか?
オブジェクト指向
- オブジェクトがあるのでオブジェクト指向
- 変数や関数を第一級オブジェクトとして扱える(コールバックなど)
- プロトタイプをベースとしたオブジェクト指向
- クラスはない
- プロトタイプとプロトタイプをチェーンでつなぐ
プロトタイプチェーン
プロトタイプを定義して、それを元にプロトタイプチェーンを作成する
Person { name: "Mike", age: "21" }
us.__proto__.__proto__
Student { student_id: "20T5054A" }
us.__proto__
UniversityStudent { society: "Poet" }
💡nameを変えると全部のチェーンが影響を受けるので、これはプロトタイプの悪い例
参照
プリミティブ(数値、ブール値、文字列)以外はすべてオブジェクト参照
- コピーが発生しない点で高速だが、オブジェクト書き換えの影響をどこで受けるかわからない(副作用)
スコープチェーン
- 簡素に捉えるならスコープはグローバルと関数の2つしかない
- 正しくは、スコープチェーンに従ってスコープは決まっている
スコープ
変数/関数が有効な範囲、生存期間を意識する
- グローバルに定義した変数/関数はグローバルにみえる
- どこからでも編集されるアンチパターン
- 名前空間の衝突を起こすアンチパターン
- 関数内で定義した変数/関数は関数のスコープに閉じる
2パス実行
JavaScriptインタプリタは2パスで動作する
- 1パス目に変数や関数の定義を洗い出す
- 2パス目に実行する
関数内スコープ
function hiyoko() {
let piyo = 'piyopiyo'
console.log(piyo)
return piyo
}
以下はエラーしない記述
function hiyoko() {
console.log(piyo) // 宣言前に
let piyo = 'piyopiyo'
return piyo
}
1パス目にpiyoが評価されるため以下と等価
function hiyoko() {
let piyo
console.log(piyo)
piyo = 'piyopiyo'
return piyo
}
global_varはすべてで有効なグローバル変数
let global_var = 'Global'
console.log(global_var)
function hoge() {
console.log(global_var)
function piyo() {
console.log(global_var)
}
}
global_or_localは定義されたスコープ内で有効な変数
let global_or_local = 'Global'
console.log(global_or_local)
function hoge() {
let global_or_local = 'Local'
console.log(global_or_local)
function piyo() {
let global_or_local
console.log(global_or_local)
}
}
関数内で定義されるグローバル
let/const/varなしで定義された関数内の変数はグローバル変数扱いになる
function hoge() {
state = 'Waiting'
return {state}
}
💡定義時は明確にlet/constを指定する
💡{state}は{state: state}に翻訳される。ただし、IEだと{state: ''}となったので注意
GC
- JavaScriptはGCを備えており、メモリ操作を行えない
- 解放されるタイミングは任意だが、参照が残るとメモリリークする
クロージャー
- 参照が切れるとGCで回収されるため、変数が存在しなくなるケースがある
- この場合、クロージャーにして参照が途切れないようにする必要がある
クロージャーの例1/2
let people = () => {
let name = 'Takeda'
return {name: name}
}
- 実行されるとnameはスコープ外になり参照が切れ、people().name = ‘Takeda’の結果が残る
クロージャーの例2/2
- 実行されるとnameはpeopleの無名関数から参照されるため、func1のクロージャーとして変数nameが残る
💡意図してクロージャーにしないと無駄に参照が残ったり、値の書き換えの影響がでる
JavaScriptの使いどころ
- クライアントサイドJavaScript
- SPA(Single Page Application)
- サーバーサイドJavaScript
- SSR(Server Side Rendering)
- BFF(Backend for Frontend)
- Server、API、DB操作
💡よいJavaScriptライフを!