blog

javascriptの再帰、クロージャ、thisオブジェクト

通常の関数呼び出し:これはウィンドウを指します。 オブジェクトとしてのメソッド呼び出し:呼び出したオブジェクトを指します。 コンストラクタの呼び出し:new演算子を使わない場合はウィンドウを指し、ne...

Sep 29, 2020 · 6 min. read
シェア

javascriptの再帰、クロージャ、thisオブジェクト

再帰

再帰関数とは何ですか?

  • プログラミング言語において、関数が直接または間接的にその関数自身を呼び出すことを再帰的と呼びます。

再帰的な特性。

  • 明確な最終条件があること
  • より深いレベルの再帰に進むたびに、問題のサイズは前の再帰より小さくなるはずです。
  • 再帰は非効率的であり、再帰のレベルが多すぎるとスタックのオーバーフローにつながる可能性があります。

arguments.calleeは実行される関数へのポインタです。そのため、これを使用して関数を再帰的に呼び出すことができます。

しかし、strictモードではarguments.calleeにアクセスできず、致命的なエラーになります。代わりに名前付き関数式を使うことができます。

function sum(num){
 if(num-1){
 return 1;
 }else {
 return num * arguments.callee(num-1);
 }
}
'use strict'
var sum = (function f(num){
 if(num-1){
 return 1;
 }else {
 return num * f(num-1);
 }
})

クロージャ

クロージャーとは何ですか?
  • は、他の関数のスコープ内の変数にアクセスする権利を持つ関数です。
  • 他の関数内の変数を読み取ることができる関数。
クロージャの3つの特性
  1. ネストされた関数
  2. 内部関数は外部パラメータや変数を参照できます。
  3. パラメータと変数は、ゴミ収集メカニズムによって回収されません。
一般的なクロージャの実装

関数の内部で別の関数を作成し、その関数をRETURNします;

クロージャを使うと、関数の外から関数内の変数を読むことができるようになるんだよ??
  • これは、内部機能のスコープチェーンが外部委託機能のスコープを含んでいるからです。

  • f1はf2の親関数であり、f2にはグローバル変数が代入され、f2は常にメモリ上に存在します。
function f1(){
 var n = 123;
 function f2(){ //f2クロージャだよ。
 alert(n)
 } 
 return f2;
 }
閉鎖の理由は?

変数にアクセスするとき、インタープリターはまず現在のスコープで識別子を探し、見つからなければ親スコープを探し、変数の識別子が見つかるか、親スコープになくなるまで探す、これをスコープ・チェイニングと呼ぶ。ES5ではグローバル・スコープと関数スコープの2つしかありませんが、各サブ関数が上位スコープをコピーし、スコープの連鎖を形成することは注目に値します。

クロージャ生成の本質は、現在の環境に親スコープへの参照があることです。

クロージャの役割
  • 匿名自己実行関数:匿名関数を作成し、即座に実行します。関数の内部変数を外部から参照できないため、関数の実行が終了するとすぐにリソースを解放します。

  • 結果をキャッシュする:クロージャは外部参照を解放しないので、このようなことができます。

    • var fn=(function(){
       var cache={}//結果をこのオブジェクトにキャッシュする
       return function(){
       var str=JSON.stringify(arguments);
       if(cache[str]){//渡されたパラメータがキャッシュに存在するかどうかを判断し、存在する場合は計算せずに結果を返す。
       return cache[str];
       }else{//計算を行い、結果を返す
       var sum=0;
       for(var i=0;i<arguments.length;i++){
       sum+=arguments[i];
       }
       return cache[str]=sum;
       }
       }
      })()
      
  • プライベートメソッドのモデリング:プライベートメソッドは、コードへのアクセスを制限するのに適しています。

    • # モジュール・パターン
      var calculator = (function(){
       var a = 1;
       function addCalculator(val){
       a += val
       }
       return {
       add1:function() {
       addCalculator(1);
       },
       add2:function() {
       addCalculator(2);
       },
       result:function() {
       return a
       }
       }
      })();
      console.log(calculator.result()); // 1
      calculator.add1();
      console.log(calculator.result()); // 2
      calculator.add2();
      console.log(calculator.result()); // 4
      
閉鎖のメリットとデメリット
  1. メリット
    1. 関数内部で変数を読むことができます。
    2. ローカル変数をメモリに保存することができ、変数が長期間メモリに保存されることを期待して、変数がデータを共有することができます。
    3. グローバル変数の汚染を避けることができます。
    4. プライベートメンバが存在します。
  2. デメリット
    1. クロージャを使用すると、関数内の変数がメモリ上に保持されたまま解放されないことがあります。
    2. クロージャは、親関数の内部で変数の値を親関数の外部で変更します。親関数をオブジェクトとして使用し、クロージャを public メソッド、内部変数を private プロパティとして扱う場合、親関数の内部変数の値を変更しないように注意する必要があります。

this

thisオブジェクトは実行時に関数の実行コンテキストに基づいてバインドされます。グローバル関数ではthisはwindowsに等しく、関数が何らかのオブジェクトのメソッドとして呼び出された場合、""thisはwindowsに等しくなります。"""this"""はウィンドウズに等しく、関数が何らかのオブジェクトのメソッドとして呼び出された場合、thisはそのオブジェクトに等しくなります。"" this はそのオブジェクトに等しい

矢印関数が矢印以外の関数に含まれている場合、this は矢印以外の関数の最も近いレベルの this にバインドされ、call(), apply(), bind() メソッドでは変更できません。"、this の値は call()、apply()、bind() メソッドでは変更できません

  1. 通常の関数呼び出し:thisはウィンドウへのポインタ。

  2. オブジェクトのメソッドとして呼び出されたもの: this これは、それを呼び出したオブジェクトを指します。

  3. コンストラクタの呼び出し:new演算子を使用しない場合、thisはウィンドウを指し、new演算子を使用してインスタンスを作成した場合、thisはインスタンスを指します。

    では、newコンストラクタは何をしたのでしょうか?

    1. 新しいオブジェクトの作成
    2. コンストラクタのスコープを新しく生成されたオブジェクトに割り当てます。したがって、thisはこの新しいオブジェクトを指します。
    3. コンストラクタのコードを実行して、新しいオブジェクトにプロパティを追加します;
    4. 新しいオブジェクトを返します。

    new演算子

    new演算子関数を自分で実装

    # 1クロージャとは、オブジェクトを生成し、それを返すオブジェクトのことである;
    function _new(){
     var obj = {}
     var constuctorFun = [].shift.call(arguments)
     obj.__proto__ = constuctorFun.prototype
     var res = constuctorFun.apply(obj,arguments)
     return res instanceof Object ? res: obj
    }
    function People(name,age){
     this.name = name;
     this.age = age;
    }
    let people2 = _new(People,'Rose',18);//カスタムcreate実装を呼び出すnew
    console.log(people2.name) //Rose
    console.log(people2.age) //18
    
  4. apply / call call: this のポインティングを変更するには apply メソッドを使用します。この関数が非制限モードである場合、グローバルオブジェクトが null または undefined で指定されると、自動的にグローバルオブジェクトを指すようになります。

  5. アロー関数:アロー関数にはthisバインディングはありません。アロー関数が非アロー関数に含まれる場合、thisは最も近いレベルの非アロー関数のthisにバインドされます。";そうでない場合、thisの値は未定義に設定されます。

Read next

データ構造 "連鎖リスト"

連鎖テーブルはノードの集まりです。各ノードは、オブジェクトへの参照を使用して後継ノードを指定します。別のノードへの参照をチェーンと呼びます。ほとんどの場合、先頭ノードはリスト全体を表すために使用されます。 リンクリストにノードを追加するには、リストの末尾までたどり、末尾のノードに新しいノードを追加します。 1つのポインタは2ステップ、1つのポインタは1ステップです。ポインタが2つの場合は...

Sep 29, 2020 · 5 min read