# JavaScript 基礎編7(学習日:9/16)(関数とスコープ、関数とthis) ## 1. 関数とスコープ ### スコープとは 変数名や関数などの参照の範囲を決めるためのもの。 原則として、スコープ内で定義された変数は、そのスコープ内のみ有効である。(ローカル変数) ### スコープの種類 * 関数スコープ 関数によるスコープを、関数スコープという。 ```javascript= function fn(){ const nijigaku = 9 console.log(nijigaku) } fn();//=>9 nijigaku;//=>Referense Error(nijigakuはローカル変数のため、関数の外からは参照不可) ``` * ブロックスコープ ブロックによるスコープをブロックスコープという。 通常ブロックのほか、if文やfor文、while文などのブロックも対象である。 * スコープチェーン スコープがネスト(二重・三重…)している場合、内側のスコープから外側のスコープ向かって変数名を探し出す。(無ければエラー) ```javascript= { const ll = "lovelive"; { const mu = "μ's"; const aq = "Aqours"; const ni = "nijigaku"; const ss = "superstar"; console.log(mu);//=>"μ's" console.log(ll);//=>"lovelive"(内→外はOK) } console.log(mu);//=>Refference Error(外→内は参照不可) console.log(ll);//=>"lovelive" } ``` * グローバルスコープ 上記のどのスコープ内にも属さず、プログラム直下に書かれた変数は、グローバル変数という。暗黙的にプログラム全体がグローバルスコープとして機能する。 もっとも外側に定義されるため、変数宣言以下のすべてのスコープで利用できる。 * ビルドインオブジェクト プログラム実行時に自動的に定義されるオブジェクト。グローバルスコープと同じく全スコープで参照可能である。 但し、ビルドインオブジェクトと同じ変数名を内側スコープ内で定義すると、内側スコープ内の変数が優先される。(変数の隠蔽) (例)undefined, isNaN, Array, RegExpなど ### 関数と巻き上げ * letとvarの違い let…変数宣言前に使用:Reference Error var…変数宣言前に使用:undefined * なぜvarはundefined? varは宣言部と代入部に分けられる。 宣言部は、自動的に最も近い関数orグローバルスコープの先頭に巻き上げられる。 したがって、暗黙的にスコープよりも前に変数宣言だけ行われた結果、例外でなくundefinedが返る。 * functionもvarと同じ性質を持つ functionもvarと同じく、関数宣言よりも前に呼び出しても、暗黙的に関数宣言が最も近い関数orグローバルスコープに巻き上げられて、関数を利用できる性質がある。 ### クロージャー * 静的スコープ 識別子がどの変数を参照するかを静的に決定する。 * ガベージコレクション 不要となった変数をメモリから開放する。 * クロージャー(関数閉包) 上記2つの仕組みを利用した、関数内から特定の変数を参照し続けることで、関数が保てる仕組み。 * クロージャーの用途 * 関数に状態を持たせる手段として * 外から参照できない変数を定義する手段として * グローバル変数を減らす手段として * 高階関数の一部分として ## 2. 関数とthis thisには様々な用途がある。以下、参照先別に変化を見る。 * 実行コンテキストにおけるthis 実行コンテキストはscript要素、type属性。 * スクリプトにおけるthis 実行コンテキストがScriptの時、トップレベルスコープのthisはグローバルオブジェクトを指す。 グローバルオブジェクト=ブラウザ→windowオブジェクト、 Node.js→globalオブジェクト * モジュールにおけるthis 実行コンテキストがmoduleの際、トップレベルスコープのthis=undefined globalオブジェクトを参照したいときはglobalThisを用いる。 * 関数とメソッドにおけるthis (1) functionメソッドの関数宣言 (2) functionメソッドを関数として定義する関数式 (3) Arrow Functionを使う関数 (4) メソッドの短縮記法 ### Arrow Function以外のthis **thisの値は実行時に決定される。** 実行時のthisの参照先をベースオブジェクトという。 * 関数機能におけるthis ベースオブジェクトが存在しないため、undefinedとなる。 ```javascript= "use strict"; function fn1() { return this; } const fn2 = function() { return this; }; // 関数の中の`this`が参照する値は呼び出し方によって決まる // `fn1`と`fn2`どちらもただの関数として呼び出している // メソッドとして呼び出していないためベースオブジェクトはない // ベースオブジェクトがない場合、`this`は`undefined`となる console.log(fn1()); // => undefined console.log(fn2()); // => undefined ``` * メソッドにおけるthis this=objとなる。 ```javascript= const obj = { // 関数式をプロパティの値にしたメソッド method1: function() { return this; }, // 短縮記法で定義したメソッド method2() { return this; } }; // メソッド呼び出しの場合、それぞれの`this`はベースオブジェクト(`obj`)を参照する // メソッド呼び出しの`.`の左にあるオブジェクトがベースオブジェクト console.log(obj.method1()); // => obj console.log(obj.method2()); // => obj ``` * thisが実行されない場合 実行時に代入されて参照先が変わってしまったり、ただの関数として呼び出される場合、ベースオブジェクトを失い、thisがundefinedになることがある。 対処法→call, apply, bindメソッド() 明示的にthisの値を指定できる。(.call(thisの値, 関数の引数…))thisがいらないときはnullが返る。 * コールバック関数とthis コールバック関数も同様の事態が起こり、thisがundefinedになることがある。 対処法→別の変数にthisを一時代入する。 Arrow Functionで記述する。 ### Arrow Functionのthis **thisの値は関数の定義時に決定される。** また、暗黙的な引数としては受け付けない。外側にthisを探しに行くが、ECMA上でキーワードであるためthisを定義できないため、必然的にエラーとなる。 this=Arrow Function自身の外側のスコープに定義されたもっとも近い関数のthisの値 コールバック関数では、1つ外側の関数のthisを参照する。呼び出し方によって変化しないため、回避策などは必要ない。 ###### tags: `JavaScript`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up