メインコンテンツへ移動

JS 学習ノート 3_関数式

無料2015-04-07#JS#js函数表达式

関数式について語れることは多い:クロージャ、this、スコープチェーン、プライベート属性。。さらに深く掘り下げれば:context、変数オブジェクト、アクティブオブジェクト、内部属性。。。

##1. 関数式と関数宣言の違い##

関数宣言には「巻き上げ」(hoisting)の特性がありますが、関数式にはありません。つまり、関数宣言はコード読み込み時に事前に context に読み込まれますが、関数式は式文を実行した時にのみ読み込まれます

##2. クロージャ##

別の関数のスコープ内の変数にアクセスできる関数。クロージャは別のスコープ内の変数にアクセスできるため、クロージャで得られる変数の値は最終値であり、その変数のある時点の値ではありません。非常に古典的な例があります:

function createFuns(){
  var result = new Array();
  for(var i = 0;i < 10;i++){
    result[i] = function(){
      return i;
    };
    
    /*
    result[i] = function(arg){
      return function(){
        return arg;
      }
    }(i);//此处匿名函数立即执行的 () 可以省略,因为 function 在等号右边出现,不存在歧义(一般形式是 (function(){})())
    */
  }
  
  return result;
}

createFuns 関数は一組の関数を返します。これらの関数の実行結果はすべて 10 です(クロージャで得られる変数の値は最終値)。しかし注釈中の方式で返される関数の実行結果は i の現在値です。値渡しだからです

##3. 関数式における this##

内部関数は外部関数内の this と arguments オブジェクトに直接���クセスできません。内部関数がこれら 2 つの変数を検索する時、そのアクティブオブジェクトまでしか検索しないからです

P.S. アクティブオブジェクトはスコープチェーンの実体であり、スコープチェーンは抽象概念ですが、アクティブオブジェクトはこの概念の具体的実装です。実際スコープチェーンはコードにマッピングすると変数オブジェクトのチェーンであり、また変数オブジェクトが出てきましたが、恐れることはありません。全く複雑ではありません:

実行環境(context)で定義されたすべての変数と関数は変数オブジェクトに保存されます。実行環境が関数であれば、その関数のアクティブオブジェクトを変数オブジェクトとし、変数オブジェクトチェーンの一環、つまりスコープチェーンの一環とします。

最初は関数のアクティブオブジェクトには 1 つの属性しかありません——arguments オブジェクト。関数内部でカスタム属性を 1 つ宣言するごとに、その関数のアクティブオブジェクトに属性を 1 つ追加します。。。

はい、これだけ語りましたが、実は一言です:this とはアクティブオブジェクト/変数オブジェクトの参照です。

まだよく分からない場合は、先輩のブログ記事 を参照してください。ついでにこの先輩の他のブログ記事もおすすめします。js に関するものはすべて素晴らしいです

##4. 変数の重複宣言##

構文エラーにはなりません。余分な宣言は自動的に無視されますが、宣言同時の初期化操作実行されます。例えば:

var x = 1;
var x = 2;//var 宣言は無視されるのでエラーにならないが、代入は実行される
alert(x);//2

##5. ブロックレベルスコープを実装する思路##

無名関数を宣言して即座に呼び出せば、無名関数内部がブロックレベルスコープになります。具体的実装:

(function(){/*ブロックレベルスコープ*/})();

注意:関数式と関数宣言の曖昧さを解消するために丸括弧が必要です(インタプリタの観点から見ればそうです)。関数宣言の後に直接丸括弧を付けることはできませんが、関数式はできます。

P.S. 示例中のコードは IIFE を実装する方式の 1 つに過ぎません。他にもいくつかあります。詳細は [javascript]IIFE 即座に実行する関数式 を参照してください。このブログ記事には詳細な比較が記載されています

##6. プライベート変数##

関数内部で var または function で宣言された変数はプライベート変数です。(インスタンスは直接アクセスできませんが、公有関数を定義してアクセスインターフェースを提供できます)

一方、this.attr = value; 方式で宣言された変数は公有変数です。(インスタンスは直接アクセスできます)

##7. クロージャ、無名関数、内部関数、内部無名関数の違い##

  • クロージャ:別の関数のスコープ内の変数にアクセスできる関数

  • 無名関数:名前のない関数式

  • 内部関数:関数内部で宣言された関数、つまりクロージャ

  • 内部無名関数:関数内部で宣言された無名関数。もちろん、これもクロージャです

P.S. クロージャを乱用すると大量のメモリを占有する可能性があります。クロージャが外側の関数のスコープ内の変数にアクセスできるのは、クロージャのアクティブオブジェクトが外側の関数のアクティブオブジェクトへの参照を保持しているからです

クロージャが破棄された後で初めて、外側の関数内の変数を破棄できます。タイムリーに破棄できないため、大量のメモリを占有する可能性があります

##8. 関数を実行する全過程##

  1. 実行環境 context を作成。context には内部属性 [[Scope]] があります

  2. スコープチェーン ScopeChain を更新

  3. アクティブオブジェクトを作成

  4. アクティブオブジェクトの this、arguments、形式パラメータなどの各属性を初期化

  5. 関数本体を実行

  6. アクティブオブジェクトを破棄(クロージャが存在する場合は破棄できません)

  7. スコープチェーンを更新

##9.js シングルトンパターンとモジュールパターン##

  • シングルトンパターン:インスタンスが 1 つだけのオブジェクトを作成するパターンの一種。说白了、パターンとは方法であり、デザインパターンとは先輩がまとめた良い方法です。js においてシングルトンパターンを実装するのは特に簡単です:

     var singleton = {attr1: value1, attr2: value2};
    

その通り、オブジェクトリテラルです。つまり無名オブジェクトを作成したことで、コンストラクタの名前が分からないので、当然 2 番目のインスタンスを作成できません

  • モジュールパターン:ダグラスがシングルトンを強化するために提案した方法。シングルトンにプライベート属性と公有属性を追加できます(時には特権属性とも呼び、プライベート属性を変更する権限がある属性を表します)。例えば:

     var singleton = function(){
       //プライベート属性
       var privateStr = 'secret';
       function addPrefix(){
         privateStr = 'this is my ' + privateStr;
       }
       
       //公有属性(特権属性)
       return{//無名オブジェクトを返す
         getStr : function(){
           addPrefix();
           return privateStr;
         }
       };
     }();//またもや無名関数の即座実行
     
     alert(singleton.getStr());
     
    

P.S. シングルトンが不要で、プライベート属性を保護するだけでよい場合は、こうできます:

function Cat(){
  //プライベート属性
  var privateStr = 'secret';
  function addPrefix(){
    privateStr = 'this is my ' + privateStr;
  }
  
  //公有属性(特権属性)
  this.getStr = function(){
    addPrefix();
    return privateStr;
  }
}
var obj = new Cat();
alert(obj.getStr());

###参考資料###

コメント

コメントはまだありません

コメントを書く