参考
【JS】ガチで学びたい人のためのJavaScriptメカニズム
あらすじ
現場でrailsを触ってlaravelを触って今はtypescriptとreact-routerで実装することが多くなってきたが、今までJavascriptをがっつり勉強してなかったので復習も兼ねて上記講座を受けてみようと思った。
とある先輩から「エンジニアじゃない人間が聞いてもわかる程度の説明にしろ」という言葉をいただいたので、できるだけ頑張る。
ブラウザとJavaScriptの関係
ブラウザには以下の要素がある
- UserInterfaceーuserに見える部分
- DataStorageーデータを保存する場所
- RenderingEnginーレンダリング(画面生成)の処理
- JavaScriptEnginーJavaScriptが動く部分
JavaScriptEnginでJSが動く。ChromeはV8というエンジン。
エンジンの中でJavaScriptやWebAPIsが動く。V8はオープンソースなのでどの環境でも使える。これをUniversalJavaScriptという。
ちなみにfirefox等ブラウザごとに個体差があるので注意。
JavaScriptコードが実行されるまで
JavaScriptはJavaScriptエンジン内で処理が行われる。
具体的にはエンジンの中、実行前に3つ要素が準備されている。
- 開発コード(自分で作ったコード)
- グローバルオブジェクト(Windowオブジェクト、中にWebAPIsが含まれる)
- this
thisに関して、thisはオブジェクトの参照を意味するもの。コンテキスト(コードの実行場所)によって取得できる値が変わる。初期値はWindowオブジェクト。
グローバルオブジェクトはJSエンジンによって生成されるコード内のどこからでもアクセスできるオブジェクト
大事なのはブラウザのグローバルオブジェクトはWindowオブジェクトとなること
実行コンテキストについて
プログラミングに関して、コンテキストとはコードを実行する際の文脈、状況である。
前述の開発コード、グローバルオブジェクト、thisをまとめたものが実行コンテキストと呼ばれる。
現在は主に以下のコンテキストがある
- グローバルコンテキスト
- 関数コンテキスト
(moduleコンテキストもあるが今はこの2つを覚えておく。evalコンテキストはパス)
グローバルコンテキストの中身
- 実行中(宣言した)のコンテキスト内の変数、関数
- グローバルオブジェクト
- this
以下のような状況がグローバルコンテキストを使用してると言える
const a = 0;
function b(){}
console.log(a);
b();
関数コンテキストの中身
- 実行中(宣言した)のコンテキスト内の変数、関数
- arguments
- (super)
- this
- 外部変数
以下のような状況が関数コンテキスト内の宣言
const a = 0;
function b(){
console.log(this, arguments, a)
}
b();
// 出力結果
// window //グローバルオブジェクト
// argumets //arguments
// 0 //外部変数
コールスタックについて
コールスタックとは、実行中のコードが辿ってきたコンテキストの積み重ね
function a(){
}
function b(){
a();
}
function c(){
b();
}
c();
chromeの開発者ツールでsourceにアクセスし、ブレイクポイントを決めてリロードすると動きが見られる。c()の時点で最初にCallStack内でanonymousが出るがこれはグローバルコンテキストの意味。進めていくとc->b->aとなり、aから消えていく。これを後入れ先だしという。
ホイスティング(hoisting)とは
コンテキスト内で宣言した変数や関数の定義をコード実行前にメモリーへ配置すること。
function a(){
console.log('a is called');
}
a();
このコードは
a();
function a(){
console.log('a is called');
}
でも動く。関数や変数は実行前にメモリへ保存されるため、コード上は後ろに書いても関数が存在している扱いになる。
各変数はどのような扱いになるか
varの場合
console.log(b);
var b = 0;
//出力結果
// undefined
実はこれでも動く。ただし出力結果はundefinedになる。
なぜこうなるかというと内部的にはこのような形になっている。
var = b
console.log(b);
b = 0
var
という値をメモリに確保して、undefinedをセットしてるからundefinedが出る仕組み。そういうふうになっている。
let、constの場合
console.log(b);
let b = 0; //またはconst
//出力結果
// ReferenceError
let
やconst
はundefinedによる初期値のセットが行われない
発展系
a();
function a(){
d();
function d(){
console.log('d is called')
}
}
// 出力結果
// d is called
// a is called
関数に関してはすでにメモリに確保されているので前に宣言していても呼べる
関数式
a();
const a = function a(){
d();
function d(){
console.log('d is called')
}
}
// 出力結果
// ReferenceError
const
宣言で関数を定義できる。それを関数式という。この場合const
扱いになるのでエラーになる。
基本は巻き上げ実装がよろしくないと思うので変数、関数はconstで実装しようって印象です。