『JavaScript言語精粋』読書ノート-関数(二)

7081 ワード

第四章関数Funnctions(二)
パラメータ
argments配列:関数は、関数宣言に割り当てられていないときに定義された形式パラメータの余分なパラメータを含むすべてのパラメータにアクセスできます.
配列「(array-like)」のオブジェクトと同様です.argmentsはlength属性を持っています.配列方法はありません.
リターン
returnは実行されます.関数はすぐに戻ります.残りのステートメントは実行しません.
  • の関数は常に値を返します.戻り値が指定されていない場合は、undefined
  • に戻ります.
  • は、newを使用して関数を呼び出し、戻り値がオブジェクトでない場合、this(新しいオブジェクト)
  • を返す.
    異常Exceptions
    異常はプログラムの正常な流れを邪魔する異常な事故です.
     try {
       if(false) {
         throw {
           name:"TypeError",
           message:"number is required"
         }
       }
     }catch(e) {
       document.write(e.name + ": "+e.message)
     }
    
    throw文は関数の運転を中断します.相手はキャッチフレーズから捕獲される.
    拡張タイプの機能
    Function.prototypeに方法を追加することにより、この方法はすべての関数に対して利用可能になる.
       Function.prototype.method = function(name,func) {
         this.prototype[name] = func;
         return this;
       }
    このように関数、配列、文字列、数字、正規表現、ブール値などの基本的なタイプのコンストラクターに方法を追加すると、プロトtypeの文字を省略できます.対応するすべての変数に変更方法を適用します.
    Numberタイプに整える方法を加えます.
       Number.method('integer',function(){
           return Math[this<0?'ceil':'floor'](this);
         });
    Stringに先頭の空白を取り除く方法を加えます.
      String.method("trim",function(){
          return this.replace(/^\s+|\s+$/g,'');
       })
    ライブラリと混用するには、この方法がないと確定した時に追加します.
     //           
     Function.prototype.method = function(name,func) {
       if(!this.prototype[name]) {
         this.prototype[name] = func;
       }
       return this;
     }
    再帰する
    直接または間接的に自身の関数を呼び出して、同じような問題のセットに分解します.
    経典の再帰問題はハノータである.塔には柱が3本(1、2、3)と直径がそれぞれ異なる中空ディスクがあります.最初の皿は小さい時から大きい順に1番目の柱に積み重ねられます.目標は2番目の柱を通って全部3番目の柱に移動します.中間に大きな皿は小さい皿に置いてはいけません.
    子問題に分解する:
  • は、1号柱の上の上から下のn-1個のディスクを3号柱で2号柱に移動させる.
  • .1号柱の一番下の皿を直接3号柱に移動させます.
  • は最後に、2号柱の上のn-1個のディスクを再帰的な呼び出し方法を利用して、全部3号柱に移動します.
  •   var hanoi = function(disc,src,aux,dst) {
        if(disc > 0) {
          hanoi(disc -1,src,dst,aux);
          document.writeln('Move disc '+disc + " from "+src+"to "+dst);
          hanoi(disc-1,aux,src,dst)
        }
      };
      hanoi(3,'Src','Aux',"Dst");
    
      //
      Move disc 1 from Srcto Dst
      Move disc 2 from Srcto Aux
      Move disc 1 from Dstto Aux
      Move disc 3 from Srcto Dst
      Move disc 1 from Auxto Src
      Move disc 2 from Auxto Dst
      Move disc 1 from Srcto Dst
    再帰的に効率的に、ブラウザ端のドキュメントオブジェクトモデル(DOM)のようなツリー構造を操作して、
     var walk_the_DOM = function walk(node,func) {
       func(node);
       node = node.firstChild;
       while(node) {
         walk(node,func);
         node = node.nextSibling;
       }
     }
    
     //    getElementsByAttribute   ,
     //                        。
     var getElementsByAttribute = function(att,value) {
       var results = [];
       walk_the_DOM(document.body,function(node) {
         var actual = node.nodeType === 1 $$ node.getAttribute(att);
         if(typeof actual === 'string' && (actual === value || typeof value != 'string')) {
           results.push(node)
         }
      });
      return results;
     }
    いくつかの言語は最終再帰的最適化を提供している.これは、関数が再帰的に呼び出された結果を返すと、呼び出されたプロセスがサイクルに置き換えられ、速度が著しく向上することを意味する.
      //           。             
      //    factorial = n*(n-1)(n-2)... 1;
      var factorial = function factorial(i,a) {
        a = a || 1;
        if(i<2) {
          return a;
        }
        return factorial(i-1,a*i);
      };
      document.writeln(factorial(4))   // 4*3*2*1 = 24
    スコープ
    作用域は変数とパラメータの視認性とライフサイクルを制御しています.
    関数のスコープ:関数内のパラメータと変数を定義することは、関数の外部では見られないが、関数内の任意の位置で定義された変数は、その関数の内部ではどこでも見られます.
    JavaScriptでは会計作用領域が不足しています.一番いい方法は関数の上部宣言関数で使用可能なすべての変数です.
    クローズド·クローズド
    関数は、作成時のコンテキスト環境にアクセスできます.
    内部関数はコピーなしで外部関数の実際の変数にアクセスできます.
    作用領域の利点は、内部関数がそれらの外部関数を定義するパラメータと変数にアクセスできることである.
    内部関数は、その外部関数よりも長いライフサイクルを持っています.
      var myObject = (function(){
        var value = 0;
        return {
          increment:function(inc) {
            value += typeof inc === 'number' ?inc :1;
          },
          getValue:function() {
            return value;       
          }
        }
    
      })()
    上で定義されているvalue変数はincrementとgetValueの方法に対して常に利用可能であるが、関数の作用領域は他のプログラムにとっては見えないようにする.
    コールバックバック
    非同期要求は、サーバの応答が到着するとすぐにトリガされるコールバック関数を提供します.
    非同期関数はすぐに戻ります.
    モジュール
    関数とクローズドを使ってモジュールを作成します.
    テンプレートの一般的な形式:
  • プライベート変数と関数を定義する関数
  • クローズド・パケットを利用してプライベート変数と関数にアクセスできる特権関数
  • を作成する.
  • は、この特権関数を返したり、アクセスできる場所に保存したりします.
  • 前に使用されたmethod方法により、Stringのためにdentityify方法を追加し、文字列中のHTML文字エンティティを探して、対応する文字に置き換える.
      String.method('deentityify',function(){
         //      ,                
         var entity = {
           quot: '"',
           lt:''
         };
        //    deetityify   
        return function() {
          //     deetityify  ,
          return this.replace(/&([^&;]+);/g,
              function(a,b){
                var r = entity[b];
                return typeof r === 'string'?r:a;
              }
          )
        }   
      }());
    最後に()演算子を使用して、作成した関数をすぐに呼び出します.これはdeentityifyメソッドです.
      document.writeln('<">'.deentityify())    // 
    カスケード
    実行後の関数をundefinedではなくthisに戻すと、カスケードを有効にします.
    一つの級聯では、一つの語句の中で同じオブジェクトを順番に呼び出すことができます.一つはAjaxクラスを有効にしています.このような形でコード化することができます.
      getElement('myBoxDiv')
         .move(300,150)
         .width(100)
         .height(200)
         ...
         .tip('This box is resizeable')
    上記の例では、コールバックの結果が次の呼び出しに使用されます.
    コリ化
    カリー化によって、関数をそのパラメータに伝えることができます.新しい関数を生成します.
      Function.method('curry',function(){
        var slice = Array.prototype.slice,
            args = slice.apply(arguments),
            that = this;
        return function() {
          return that.apply(null,args.concat(slice.apply(arguments)))
        }
        })
    
     function add (a,b) {return a+b}
     add.curry(1)(6) //7
    記憶
    関数は、以前の操作の結果をあるオブジェクトに記録し、無駄な反復演算を避けることができます.この最適化は記憶と呼ばれます.
    Fibonacci数列を例にとって、一つのFibonacci数字は前の二つのFibonacci数字の合計です.一番前の二つの数字は0と1です.
     var fibonacci = function (n) {
       return n<2? n:fibonacci(n-1) + fibonacci(n-2)
     }
     for(var i =0 ;i< = 10;i+=1) {
       document.writeln('//'+i+': '+fibonacci(i))
     }
    
     //0: 0
     //1: 1
     //2: 1
     //3: 2
     //4: 3
     //5: 5
     //6: 8
     //7: 13
     //8: 21
     //9: 34
     //10: 55
    修正して、memo配列を利用して私達の保存結果を保存して、結果を保存して閉じている中で隠れることができます.
      var fibonacci = function() {
        var memo = [0,1];
        var fib = function(n) {
          var result = memo[n];
          //          ,      ,         
          if(typeof result !== "number") {
            result = fib(n-1) + fib(n-2);
            memo[n]= result;
          }
          return result
        };
        return fib;
      }();
      fibonacci(10)  //55
    これを押すと、メモリ機能付きの関数を作成してくれます.
      var memoizer = function(memo,formula) {
        var recur = function(n) {
          var result = memo[n];
          if(typeof result !== "number") {
            result = formula(recur,n);
            memo[n] = result;
          }
          return result;
        };
        return recur;
      }
      var fibonacci = memoizer([0,1],function(recur,n) {
          return recur(n-1) + recur(n-2);
        });
      fibonacci(10)  // 55
    『JavaScript言語精粋』読書ノート-関数