Skip to content

Latest commit

 

History

History
676 lines (618 loc) · 38.3 KB

OUTLINE.md

File metadata and controls

676 lines (618 loc) · 38.3 KB

OUTLINE

字句構造

Strict mode

  • @未使用
    • ガーベジコレクションの簡単な説明
let array = [ 1,2,4];
array = [10,2,3,0];
// この時最初に代入されていた配列のオブジェクトは参照できなくなる
// => GCされる

オブジェクト

  • 目的
    • オブジェクトの作り方、アクセス方法について学ぶ
    • オブジェクトはすべてのオブジェクトの元となっていることを学ぶ。
    • Objectのインスタンスメソッドの使い方と継承について学ぶ
    • Objectの静的メソッドの使い方について学ぶ
  • サマリ
    • オブジェクトはプロパティの集合のことで、連想配列に近いですがキーには文字列かSymbolのみが利用できます。キーにオブジェクトを利用する場合はMapオブジェクトというものを利用できます
    • JavaScriptのほぼすべてのオブジェクトがObjectコンストラクタを継承しています。
    • プリミティブ値も、それぞれコンストラクタとなるオブジェクトが存在し、それらはObjectコンストラクタを継承しています。
      • nullundefinedを除いたもの
      • この2つは toStringとやった場合に次のようなエラーがでます
    • そのため、それぞれのプリミティブ値もオブジェクトコンストラクタのインスタンスメソッドとして定義されているものは利用できるようになっています。
    • そのため、Objectのインスタンスが利用できるメソッドはObjectを通じて利用できます。
    • また、Objectの静的メソッドは便利なものが用意されているので、簡単な使い方を見てみます。
  • アウトライン
    • オブジェクトとは
      • オブジェクトはプロパティの集合
      • オブジェクトリテラルで作成できる
      • ショートハンドで書ける
      • 値は何でも格納できるけど、キーはプロパティ名は"文字列"となる
        • これは数値や関数を渡した場合に勝手に文字列化される
      • 連想配列とかハッシュとか言われることがある
      • キーにオブジェクトが使えるのはMap
        • そのため連想配列とは若干違う
    • オブジェクトへのアクセス
      • プロパティへのアクセス方法が2種類ある
        • 簡単で分かりやすい方法
          • ドットを繋げてのアクセス方法
        • 読みにくいけど動的な方法
          • ブラケット記号によるアクセス方法
          • ブラケットは変数をプロパティ名に利用できたし、ドットでは書けない文字列もプロパティにできる
      • オブジェクトへの追加
        • 変数をプロパティ名に利用する
        • ブラケット記法の 対となる Computed Property
      • オブジェクトのショートカット
        • { key }
    • オブジェクトの静的メソッド
      • Object.keysObject.valuesObject.entries
        • こいつらはIterableじゃなくて普通に配列を返す
        • Object.keysでマージ?
      • Object.assign({})でコピー
      • Object.is
        • ===では+0-0は区別しない、またNaNは区別される
        • このメソッド自体は重要ではないが、この比較ロジックが他でも利用されている
    • オブジェクトのインスタンスメソッド
      • プロパティの存在確認
      • プロパティがあるかを確認する方法としては in 演算子 か hasOwnPropertyが利用できる
        • in演算子は継承元(親)が持っている場合もtrueを返す
          • toStringなどは親が持っているのでtrue
        • hasOwnProperty はオブジェクト自身が持っているならtrueを返す
          • {}.hasOwnProperty("toString")// falseということ
    • オブジェクトはすべての元
      • プリミティブ以外はすべてがオブジェクト
      • JavaScriptのほぼすべてのオブジェクトはObjectクラスを継承している
        • ObjectのインスタンスはObject.prototypeを継承
        • これによりin演算子とObject#hasOwnPropertyメソッドの違いが起きてる
        • Object.createを使ってオブジェクト継承を表現できる
      • Arrayを例にしてみる
        • ArrayのインスタンスはArray.prototypeを継承
        • Array.prototypeObject.prototypeを継承
        • これをprototype継承と呼ぶが詳しくはあとで
        • 結果として、Objectのインスタンスが持つメソッドは、他のオブジェクトからも利用できるということ
      • 殆どのオブジェクトが文字列にできるのもObject#toString()が継承されているから
      • 関数、正規表現、文字列オブジェクト、数値オブジェクト、真偽値オブジェクト、配列、Map、Setとにかく何でも
    • [コラム] Object.create(null)
      • Objectはすべてのオブジェクトの元といったけど例外があります。
      • それがObject.create(null)です。
      • プロパティの値が関数であるものがメソッドと学びました
      • そしてObjectのインスタンスはtoStringなどのメソッドを始めから持っていることを知りました
      • ここである問題があることに気づきます。
      • 任意の文字列をキーにするオブジェクトを作るときに toString 始めからプロパティとして存在することが分かります。
      • この問題を解決するには、オブジェクトではなくMapを使うか、もしくはメソッドを持たないObjectを作れば良いはずです。
    • Object.assign
      • 複製とマージに使えるコピーメソッド
      • コピー
        • あるものをすでにあるところへコピーすること
      • 複製
        • あるものを元に新しく同じものをつくること
      • マージするときは空のオブジェクトを起点にする
      • 複製は空のオブジェクトへマージすることで表現できる
      • 基本的にshallow copyであることに注意が必要
      • deep copyは再帰的にshallow copyすることで実現できる
      • 同様に、JavaScriptでは基本的にshallowなものばかり
        • Array#slideArray#flattenなど
      • そのためユーザーランドのライブラリに一般にある機能が多い
        • npmというパッケージ管理ツールでそのエコシステムが成り立っている
  • 未使用
    • コンストラクタとリテラル
      • new演算子
      • コンストラクタ
      • リテラル
    • new 演算子とインスタンス
    • ラッパーオブジェクト
      • プリミティブ値はオブジェクトではないけど、プリミティブ値にもラッパーオブジェクトというオブジェクト版がややこしい。
      • プリミティブな値を[[Get]]するときにToObjectされてできるのがラッパーオブジェクト
      • ラッパーオブジェクトについては基本的に使い道がほぼないので気にしなくて良い。
      • プリミティブのラッパーオブジェクトは型変換ぐらいしか利用しない。
    • ObjectのStatic method
    • この継承の仕組みがprototypeチェーンであり、それについてはFunctionで詳しくやるのでココでは解説しませんが、クラス継承をJavaScriptではどのようなしくみでうごいているかという点について
    • Object.isは同値性を判定するメソッド
      • +0-0の違いが必要になる場面で必要だけど滅多にない

配列

  • この章では、配列の基本的な操作と配列を扱う場合においてのパターンについて学びます。
  • 配列の作り方、取り出し方、データ探索、削除について学んでいきます。
  • サマリ
    • 配列は特別なオブジェクトです。まずは配列の作り方と配列への要素の追加方法、配列から値を取り出す方法、配列に値がはいってるかを確認する方法を見ていきます。
    • また配列はlengthが特別な動きをするため、lengthを変更することで値を削除することもできますが、spliceなどの削除方法について見ていきましょう。
    • そして、配列は破壊的な操作と非破壊的な操作が混在する分かりにくい部分を持ち合わせています。そのため、非破壊的に扱う方法を学ぶことでより安全な配列を利用できます。
    • 配列自体が拡張に拡張を重ねた仕様であるため、Lodashのように扱い方を統一したライブラリなども多いです。
    • また配列は 0以上の値を扱うことができるため、空の配列を使うことで値が無い場合とある場合にも同じ操作ができるためパターンとして優れています。
    • そのためには色々なものを配列にする方法を見ていきましょう
  • アウトラインの流れ
    • 配列の基礎
      • 読み込み
      • 書き込み
    • 配列の応用
      • 配列と他のオブジェクトでのやり取り
  • アウトライン
    • 配列は特殊なオブジェクト
      • 配列とは値に順序つけて格納したもの
      • 配列の中身の値のことを要素、それぞれの要素の位置のことをインデックスという
      • 配列は可変な配列のみ
      • lengthは自動的に追従する
        • array[array.length] = 1lengthが自動で増える
      • typeof をすると "object"
        • 分類としてはオブジェクト
      • 配列かどうかを判定 Array.isArray を使う
    • [コラム] TypedArray
      • TypedArrayとは
      • Arrayとの違い
    • 配列の作成とアクセス
      • 配列の宣言には [] リテラルが使える
      • array[num] でアクセスできる
      • arrayのインデックスは 0 から開始されます
      • 配列の末尾の要素へのアクセスは length - 1 を使う
      • 存在しないインデックスへのアクセスはundefinedが返される
      • オブジェクトで存在しないプロパティへアクセスしたのと同じ
    • 配列から要素を検索
      • 存在(真偽値)
        • 配列に含まれているかはArray#includesArray#someで見つけられる
      • インデックス
        • Array#indexOfArray#findIndexでindexを取ることができる
      • 実体
        • 配列から要素を取り出す場合は Array#findを使う
      • なぜそれぞれの方法が用意されているのか?
      • 読む人のコストの低い明示的な書き方と処理コストが主な理由
      • indexOfincludesの比較
    • 配列と破壊的、非破壊的
      • MutableかImmutableか
      • 基本的に破壊的なAPIと非破壊的なAPIが混在している
    • 配列へ要素を追加と削除(破壊的)
      • 末尾
        • Array#push
        • Array#pop
      • 先頭
        • Array#unshift
        • Array#shift
    • 配列から要素を削除(破壊的)
      • 配列から要素を削除する方法も色々ある。
      • 基本的にはArray#spliceを使うのが簡単だけど、これは破壊的な操作
        • 削除と追加を同時に行うという特殊な感じのメソッド
      • 空の配列を作りたいなら .length = 0を使うこともある
      • けど、普通は新しい配列を作って変数を上書きしちゃうのが楽です。
    • 疎の配列を作る
      • new Arraylengthを指定した配列を作る
        • 疎の配列は基本的に扱いにくく誤解の元となるため避ける
        • パフォーマンス的にも問題になりやすい
        • Array.ofかリテラルを使う
    • Array-likeとは何か
      • lengthと順番をもったオブジェクトのこと
      • ただし length が配列のように自動的に更新されない
      • また、Array.prototypeではないのでArrayのメソッドをもっていない
      • Arrayのようなオブジェクトのこと
      • DOM Node、arugmnent
      • Array#fromで配列にできる
    • 配列をコピー
      • 配列は参照型
        • 配列はオブジェクトであるため参照型
        • 破壊的な変更は参照先にも影響を与えしまう
        • 配列は基本的に破壊的な操作になってることが多い
      • Array#sliceまたはArray#concat
      • Array#copyはない
      • 破壊せずに扱うならコピーするか破棄せずに変更を加える事ができるメソッドを使う
    • 高階関数とメソッドチェーン
      • これについてはLoopのところで少しやっているが、基本的に配列の中身をすべて走査するため一見処理コストはあるが、膨大な数にやセンシティブな状況でなければこれらの高階関数で配列を扱ったほうが安全で読みやすいコードになる。
      • なぜ読みやすいコードになるかというと、手続きではなく、処理を関数(大体は無名関数だが)にして扱うため処理のまとまりが生まれやすい。
    • パターン: nullを返さずに配列を返す
      • また null を返すパターンなどが減るため、常に配列を受け取り/必要なら配列を返すというパターンが出来上がるところが良いところ。
      • nullを渡すな空の配列を渡せ、nullを返すな空の配列を返せ
  • 未整理
    • push/pop/shift/unshift
    • Arrayの要素がないことは hasOwnPropertyを使うことで判定できます。
    • 配列は特殊なオブジェクトです。
    • 格納した要素はキーに数字を使って取り出せます。
    • Array#concatArray#slice = 新しい配列
    • とにかく配列メソッド(操作)には一貫性がないような感じなので、自分で一貫性を持った扱い方を決めた方が良い。 - Array methods - Immutable or Mutable
    • Arrayと高階関数
    • 配列から他のデータ型にする場合で考えるのは、ほぼ文字列ぐらいなのでArray#joinArray#mapを使うなどが定番のやり方
    • Arrayのパターン
      • Array -> Array
        • slice、concat、mapなどに代表されるコピーを作って返す操作
      • Array -> void(破壊的)
        • pushやshiftに代表されるArrayに破壊的な操作
      • Array -> String
        • joinなどの文字列
      • Array -> Boolean
        • indexOfやincludes等の操作
        • Array.isArrayは特殊なものでArrayかどうかを判定できる
          • Realmが異なるとArrayはinstanceofでも一致しなくなるため
      • Array -> any
        • findなどのArrbayからものを取り出す操作
        • 探索処理を書く際には必須だが
        • JavaScriptのデフォルトは大体が線形探索担ってる
      • Other -> Array
        • Array#fromArray#of
        • Array-likeという概念がある
        • これもやっぱりArrayは特殊なオブジェクトであるから
        • exitic objectについて
      • new Arrayは引数の数で壊れてる
        • Array.ofを使ってリテラルのように配列を作る

String

  • テーマ
    • JavaScriptにおける文字はユニコードに従っていること
    • 基本的な文字操作と配列との違い、正規表現との関連について学んでいく
    • JavaScriptにおいては特に文字において苦戦する要素は少ないが、UTF-16を扱うためサロゲートペアの問題があることは知っておく
    • 目的な文字列を組み立てる方法を学んでいきます。
  • アウトライン
    • 文字列の宣言は、リテラルを使う
      • ""
      • ''
      • テンプレートリテラル
    • 文字とはなにか
      • UTF-16 code unitsのシーケンスである
      • Code unitは \uHHHH と表現することができる
      • またCode Unitはサロゲートペアの問題がある。
      • Code Pointは\u{HHHHHH}として表現できる
        • これは1個または2個のCode Unitをまとめたもの
      • char
      • charCode
      • code unit
    • 文字列の分解
      • インデックスでのアクセス
      • String#slice, String#substring
    • 文字列の結合
      • 加算演算子
      • string += "String"
      • 変数と文字列の結合にはテンプレートリテラルを使う
    • 文字列の比較
      • ===で文字列を比較する
      • また>は辞書順
    • 文字列の検索
      • 部分文字列の検索
        • インデックス
          • 対象文字列.indexOf("検索文字列"): インデックス
        • 真偽値
          • 対象文字列.startsWith("検索文字列"): 先頭にあるか
          • 対象文字列.endsWith("検索文字列"): 終端にあるか
          • 対象文字列.includes("検索文字列"): 含むか
      • 正規表現の検索
        • 真偽値
          • String#startsWith: /^検索文字列/.test(対象文字列)
          • String#endsWith: /検索文字列$/.test(対象文字列)
          • String#includes: /検索文字列/.test(対象文字列)
        • インデックス
          • String#indexOf: 対象文字列.search(/検索文字列/)
        • 詳細な情報
          • String#matchString#exec
      • 文字列と正規表現の違い
        • 意図の表明
        • 正規表現にはコメントが必要
    • 文字列の置換/削除
      • String#replaceを使う
      • 削除は空文字列への置換
      • 第二引数の関数を使った高度な置換
    • [コラム] 文字列と正規表現
      • Symbolで同じ処理を共有している
    • 構造的な文字列の組み立て
      • 文字列を操作してやりたいことは最終的に目的の文字列を組み立てることです。
      • 多くは文字列の結合や削除だけで目的を満たせますが、構造的な意味を持つ文字列の場合は、専用の処理を書く必要が出てくる場合があります。
      • 例えばある文字列同士からURLを生成したい場合
      • DOMならURL、Node.jsならpathモジュール
      • タグ付きテンプレート
        • DSLを表現できる
      • HTMLエスケープの例
        • コンテキストを考慮しないと安全な文字列結合が難しい
  • 未使用
    • 文字列はImmutableな値であるので、削除も新しく文字列を作って返すようになってる
    • Immutableであることがオブジェクトとの大きな違い
    • 文字列をコピーするメソッドは必要ない
      • コピーは var x = strfn(str) とというときにコピーされるということ
    • 文字列の知りたいこと分類
      • 作成と取得
        • リテラル、インデックス
        • sliceとstubstring
        • padStart/padEnd
        • コラム なぜ start/end?
        • 結合、分解
      • 文字列組み立て
        • URL、Path、HTMLなど
        • タグ付きテンプレート
      • フォーマット
        • テンプレート、trim
      • 検索/置換
        • search、replace、startsWith、includes
        • <=> 正規表現
      • ユニコード
        • サロゲートペア
        • UTF-16
        • 文字 = . /regexp/u

正規表現

  • 正規表現は正規表現リテラルと正規表現オブジェクトがある
  • 基本はエスケープが不要なリテラルで
  • 正規表現オブジェクトは動的に正規表現を組み立てたい場合に利用する
    • 特殊文字には二重エスケープが必要であるため記述が面倒
  • 正規表現はStringと組み合わせて利用する
    • 文字列が正規表現にマッチするかテストする
    • 文字列からマッチする文字列を取り出す

未使用

ラッパーオブジェクト

  • "string".toString()が呼べる理由を理解する
  • ラッパーオブジェクトはプリミティブ型の値に対応するオブジェクト
  • プリミティブ型の値は評価時に自動的にラッパーオブジェクトへ変換される
  • ラッパーオブジェクトも評価時にプリミティブ型の値が取り出される
  • 基本的にはラッパーオブジェクトを使う理由がない
  • typeofの問題もあるため
  • 普段は意識する必要がない

配列: Array#slice

  • 目的: 配列から指定範囲の要素を取り出すには、Array#sliceの動作について学ぶこと
  • String#sliceと同様で、範囲を指定して新しい配列を作って返す
  • 具体例: 第一引数のみはそれ以降
  • 具体例: 第二引数を指定すれば範囲指定になる
var array = ["A", "B", "C", "D", "E"];
console.log(array.slice(1)); // => ["B", "C", "D", "E"]
console.log(array.slice(1, 5)); // => ["B", "C", "D", "E"]
// マイナスを指定すると後ろからの位置となる
console.log(array.slice(-1)); // => ["E"]
// 位置:1から4の範囲を取り出す
console.log(array.slice(1, 4)); // => ["B", "C", "D"]
// 第一引数 > 第二引数の場合、常に空配列を返す
console.log(array.slice(4, 1)); // => []

配列: 破壊的メソッドと非破壊的メソッド

  • 目的: 配列の破壊的なメソッドと非破壊的メソッドの違いについてを知ることは重要です。
    • 破壊的なメソッドとは、配列オブジェクトのプロパティそのものを変更し、配列または変更理由を返すメソッドです。
    • 非破壊的メソッドとは、配列オブジェクトのコピーを作成してから値を変更し、そのコピーを返すメソッドです。
    • 配列の要素を変更するメソッドには、これらの破壊的メソッドと非破壊的メソッドが混在しています。
  • 具体例:
    • 破壊的なメソッドの例としてはArray#pushがあります。
    • 非破壊的メソッドの例としてはArray#concatがあります。
    • どちらも既存の配列に値を追加することができる点は同じです。
    • 動作: Array#pushでは配列を破壊的に操作する
    • 動作: Array#concatは新しい配列を作り値を結合する
  • 必要性: 関数で配列を処理する際に受け取った配列を破壊することは問題となることがあるためです。
    • 具体的なコード例
  • 解決方法: 破壊的なメソッドは配列をコピーしてから操作することで解決できます。
    • 対策: sliceconcatを使ったコピー
      • sliceやconcatは引数なしの場合、単純に配列のコピーを返すことが知られています。
    • 対策: ライブラリを利用した方法
      • immutable-array-prototypeやlodash、immutable.jsなど多用なライブラリが存在しています。

配列: Array-like

  • 目的: Arrayのようなオブジェクトについて知る
  • 問題点: JavaScriptには配列のように扱えるが配列ではない、Array-likeと呼ばれるオブジェクトがあります。Array-likeオブジェクトとは配列のようにインデックスでアクセスでき、配列のようにlengthプロパティも持っていますが、配列のメソッドは持っていないただのオブジェクトのことを言います。
    • 具体的なコード例
  • 具体例: Array-likeオブジェクトの例としてargumentsがあります。
    • argumentsは関数の引数を順番に格納したArray-likeオブジェクトです。
    • 文字列もArray-likeですが、"文字列"という性質やIterableという性質を合わせ持っています。
  • 違い: Array-likeと配列の大きな違いは、Array-likeはArrayのインスタンスではないため、配列が持つメソッドを持っていない点です。
    • たとえば、Array#map`のようなメソッドはArrayのインスタンスではないArray-likeオブジェクトには存在しません。
  • 判別: Array-likeか配列なのかを見分けるにはArray.isArrayメソッドを利用できます。
    • Array-likeは配列ではないので結果はfalseとなります。
    • 先ほど配列のメソッドを持ってないと言いましたが、オブジェクトには任意のメソッドを実装できるので、mapメソッドを持ったArray-likeオブジェクトを作ることもできます。
    • そのため、Array-likeか配列なのかは、メソッドを持っているかではなくArray.isArrayメソッドで見分けるのが簡単で確実な方法です。
  • 変換: Array-likeを配列にするにはArray.fromメソッドが利用できます。
    • なぜ: Array-likeは配列の便利なメソッドがないため、forループなどで展開しないといけないの手間となるため。
    • Array-likeを配列に変換することで配列と同じように便利なメソッドがりようできるので配列に変換してから処理することが多い。

配列: map/filter/reduce

  • map
  • forEach
  • filter
  • reduce

配列: メソッドチェーン

  • 目的: 配列でよく見かけるパターンであるメソッドチェーンがどのような原理で動いてるかを知る。
  • 配列でメソッドチェーンを利用するのは処理を一つのまとまりとして定義し、繋げることができるから
  • 具体例: メソッドチェーンをしない場合との比較
  • メソッドチェーンがどのような仕組みで動いているのかを確認する
    • 具体例: map(a => a * 2).filter(a => a > 10)
    • 具体例: アイテムの配列から特定の値段以上の名前を取り出す
  • 必要性: メソッドチェーンを利用すれば途中の一時的な変数を作る必要がなくなります。
  • あまりに長いメソッドチェーンはあまりに長い関数と同じように読みにくくなりますが、適度な単位で処理を続ける場合にはメソッドチェーンを利用することで簡潔に処理を書けるようになります。
  • メソッドチェーンは配列だけではなく、自作のクラスや文字列など様々な場面で利用されます。
  • 有名なところではjQueryはメソッドチェーンを多用したライブラリです。
  • 配列には配列を返すメソッドとしてArray#mapやArray#filterがありこれを利用した配列の加工処理がメソッドチェーンで書かれることが多いです。

関数

関数の宣言については関数と宣言 · JavaScriptの入門書 #jsprimerで紹介している。 宣言は単なるシンタックスなので、関数の機能や挙動についてを目的にした章。

関数の目的

  • 目的: なぜ関数学ぶ必要があるのか
  • アプリケーションを作る場合において、用意された処理だけでは足りません。
  • そのため目的に沿った関数を自分で作成する必要があります
  • そもそも関数とはある入力に対してある出力を作り出し返すものです
  • 目的に沿ったものを作れるようになるには、様々な関数の機能を知ることが大切です。
  • またある目的ことにパターンが存在し、これはオブジェクト指向プログラミングや関数型プログラミングなど
  • 目的: 関数を使った小さなユースケースを満たすプログラミングを考える

関数の章の分解

  • 関数の宣言
  • 関数とスコープ
    • var,let,const
  • 関数の呼び出し
    • this,new.target
  • クラス
    • prototype

スコープ: var,let,const

  • 目的: 関数の中から変数へアクセスするとどのような動きをするのかを理解する

スコープの要素

  • 機能: 関数はスコープを作り出します
  • スコープを賢く使うことで読みやすいコードを書くことができ、また意図しない
  • 命名:そのときにブロックを使っているこれがいわゆるスコープ
  • 名前解決: スコープの中にある変数は外からアクセスできない
    • 引数はスコープの中にある変数?なので外からはアクセスできない
      • 例外: argument.callee.caller
  • 機能: 逆にスコープの中から外にある変数へアクセスすることはできる
  • 具体例: swithchをスコープに閉じ込めて結果だけを取り返す方法
  • 誤解: スコープの中にある変数は、その関数が終了したから消えるわけではない。
  • 実際: アクセスがなくなったときに初めて消える = ガーベージコレクション
    • 確認: ガーベージコレクションは仕様ではどのような表現?
  • 分類: 静的なスコープと動的なスコープ
    • ある変数がどのスコープにあるのかは見て分かる
    • スコープには関数スコープ、catchのスコープなど何種類化ある
    • 基本的には { }で囲まれたブロック
    • スコープにLexiacal Envという変数が作成され、変数はこのEnvに紐付けられる
    • 静的なスコープ
      • functionや
    • http://azu.github.io/annotation-memo/es6-draft/
  • 関連: スコープと変数宣言
    • スコープと変数宣言には大きな関連があります。
    • なぜならletconstfunction文などはすべてそのスコープへ変数を宣言して値を関連付けるたです
  • 分類: グローバルスコープ
  • 分類: ブロックスコープ
  • 機能: スコープチェイン
  • 名前解決: スコープ間で同じ変数の定義とshadowing
  • [コラム] スコープは小さく、変数の影響範囲は小さく
    • 変数を不用意にグローバルに書いてしまうと影響範囲がお多い
    • そのため必要なスコープで必要な変数を定義する
    • 複数のスコープで共有する変数は?
      • => いわゆるデザインパターンの世界
    • 必要なスコープで必要な変数を定義する
  • 活用: クロージャー
  • [コラム] hoisting、funcitionとvar fn =function、TDZ
  • 未使用
    • 参照できない変数を参照した時のエラー

Note:

スコープの説明パターン

関数とスコープ: なぜスコープは大事?

  • スコープと名前解決
    • プログラミングで重要な概念は値を変数に保存して、必要なときに取り出して使うことです
    • 関数も値であるので、関数を変数に保存して、必要な処理を再利用できます
    • しかし変数は同じ名前をスコープに宣言することはできません
    • 何かアプリケーションを作成する際に、あらゆるところから取り出す必要がある値よりも一時的な値、つまり一時的な変数の方が多いです
    • つまり、ひとつのグローバルスコープへすべての変数を定義する必要性はありません
    • むしろ変数は必要なスコープの中でのみ扱い、その中で完結することが見た目どおりのコードへつながります
  • 関数とプログラミング
    • 関数を使わなくてもプログラミングはできます
    • 多くのプログラミング言語は人間が書くために作られたものです
    • すべての処理を関数を使わずに書くこともできその処理結果は同等です
    • しかし次のように関数を使うことで人間が読んで分かるコードを書きやすくなる

関数とスコープ: 未使用

擬似コードでのスコープ

const globalScope = {
    outer: null, // <= globalより外側のスコープはないためnull
    envRec: new Map(), // <= envRecはスコープ毎に作られる
};
// globalスコープには`outer`変数が定義されていり
// 変数はglobalスコープのenvRecに記録される
globalScope.envRec.set("outer", "out");

// function宣言により関数fnのスコープを作成する
const fnScope = {
    outer: globalScope, // <= 現在の実装スコープ = globalScope
    envRec: new Map() // <= envRecはスコープ毎に作られる
};
// function fnの中の変数処理
// `arg` 仮引数はfnScopeのenvRecに記録される
fnScope.envRec.set("arg", 1);
// 関数スコープ内で宣言された`inter`変数もfnScopeのenvRecにされる
fnScope.envRec.set("inter", "in");
// fnScopeのなかで`outer`変数を参照する
// この時のcurrentScopeはfnScope
getValue("outer", fnScope);

function getValue(variableName, currentScope) {
    if (!currentScope) {
        throw new Error(`変数:${variableName}は定義されていません`);
    }
    // 現在のScopeのenvRecに変数が定義されているならそのenvRecから取り出す
    if (currentScope.envRec.has(variableName)) {
        return currentScope.envRec.get(variableName);
    } else {
        // ない場合は、outerのscopeに訪ねに行く
        return getValue(variableName, currentScope.outer);
    }
}

Arrow Functionとthis

削った章

  • Number
  • Generator/Iterable/Iterator
  • ビルトインオブジェクト
    • Symbol
  • Proxy/Reflect API