「JavaScriptモード」読書ノート(2)—基本テクニック2

9684 ワード

前の篇では、簡単にいくつかのjsコードの基本的なテクニックを紹介しました.この文章は続きます.for forループは、引率(argments)やHTML容器(HTMLColltion)オブジェクトなどの配列またはクラスのオブジェクトを巡回する際によく使われます.通常forサイクルモードは以下の通りです.
for(var i = 0; i < myarray.length; i++) {
    //  myarray[i]   
}
このモードの問題は、繰り返しのたびにデータにアクセスする長さである.これはよくないです.だから:
for(var i = 0, max = myarray.length; i < max; i++) {
    //  myarray[i]   
}
このようにして、まず長さを記憶しておけば、毎回の循環ごとにデータの長さにアクセスすることができなくなります.特にいくつかのDOM操作では、アクセスの速度が遅い.
下記は単一変数モードで、変数を循環以外に置くこともできます.
function looper() {
    var i = 0,
        max,
        myarray = [];
    // ...
    for (i = 0,max = myarray.length; i < max; i++){
        //  myarray[i]
    }
}
このモードの利点は単一変数のモードを貫いているので一貫性にある.欠陥はコード作成時の接着とコピーのサイクル全体が面倒です.例えば、1つの関数から別の関数にコピーするには、iとmaxを新しい関数に運ぶことができるようにしなければなりません.これらの量は希望関数では必要ないなら、削除される可能性があります.ここでのコピーは単に他のところに行くというのではなく、jsのコード多重モードによって他の関数で使用されることに注意してください.
サイクルの最後の改良には、i++を使って、次の2つの表現を置換します.
  • i=I+1
  • i+=1
  • forモードの重い二つの変数はいくつかの細かい動作を引き出しています.
  • 最も少ない変数(最多ではなく)を使用した
  • 1歩0に減らすのが一般的で、0と比較するのは同じ配列の長さよりも、あるいは0でない配列の方が効率的です.
  • 最初の変更後のモード:
    var i ,myarray = [];
    for(i = myarray.length; i--;){
        //   myarray[i]
    }
    
    二つ目はwhileサイクルを使用します.
    var myarray = [],i = myarray.length;
    while(i--){
        //  myarray[i]
    }
    
      
    二、for-i nサイクル
     for-inサイクルは、非配列オブジェクトを巡回するために使用されるべきである.for-innサイクルを使用してもエニュメレーションとなります.技術的には、for-i-nサイクルを使用して配列を巡回することができます(JavaScriptでは配列も対象ですので)、しかし、配列オブジェクトがすでにカスタム関数によって拡大されている場合、論理的なエラーを引き起こす可能性があります.
    var myarray = ['a','b','c','d'];
    for(var i in myarray) {
        console.log(i)
        console.log(myarray[i])
    }
    
    オブジェクト属性を巡回して、プロトタイプチェーンに遭遇する属性をフィルタリングする場合には、ハスOwnProperty()法を使用することが重要である.たとえば:
    var man = {
        hands:2,
        legs:2,
        heads:1
    }
    
    //       
    //             
    if(typeof Object.prototype.clone === 'undefined'){
        Object.prototype.clone = function () {};
    }
    //    
    for(var i in man) {
        console.log(i + ':' + man[i])
    }
    
    あるいは、これこそあなたが欲しいものです.
    var man = {
        hands:2,
        legs:2,
        heads:1
    }
    
    //       
    //             
    if(typeof Object.prototype.clone === 'undefined'){
        Object.prototype.clone = function () {};
    }
    
    for(var i in man) {
        if(man.hasOwnProperty(i)) {
            console.log(i + ':' + man[i])
        }
    }
    
    じゃ、Object.hasOwnPropertyの方法は何ですか?メソッドはブール値を返します.オブジェクト自体の属性に指定された属性があるかどうか(つまり、指定されたキーがあるかどうか)を示します.これはMDN上の言い方です.つまり、この方法は、この属性がオブジェクト自身の属性であり、他のソース(例えばプロトタイプチェーン上の属性)ではないかを教えてくれます.
    もう一つのハスOwnProperty()を使用するモードは、Object.propertyでこの関数を呼び出します.例えば、
    for(var i in man) {
        if(Object.prototype.hasOwnProperty.call(man,i)) {
            console.log(i + ':' + man[i])
        }
    }
    
    ハスOwnPropertyを使用してマンオブジェクトを精錬した後、名前の衝突を効果的に回避することができ、比較的長い属性名をローカル変数を使用してキャッシュすることもできます.
    var i,
        hasOwn = Object.prototype.hasOwnProperty;
    
    for(i in man) {
        if(hasOwn.call(man,i)) {
            console.log(i + ':' + man[i])
        }
    }
    
    注意:厳密にはハスOwnProptyを使わないのは間違いないです.具体的なタスクとコードに対する自信に依存して、この方法を省き、サイクルの実行速度を少し速めることができます.ただし、対象の内容が確認できない場合(プロトタイプとチェーン)は、ハスOwnProperty()のようなセキュリティチェックが必要です.
    フォーマットのバリエーションがありますが、個人的にはこのような使い方を勧められません.
    var i,
        hasOwn = Object.prototype.hasOwnProperty;
    
    for(i in man) if(hasOwn.call(man,i)) {
        console.log(i + ':' + man[i])
    }
    
    唯一の長所はかっこを省くことですか?
     
    三、内蔵の原型を増やさないでください.
    構造関数のプロトタイプ属性を増加させることは,機能性を増強する強力な方法であるが,この方法が強すぎる場合がある.内蔵コンストラクタ(Object(),Aray(),Function()などのプロトタイプを増やすことは魅力的ですが、これはメンテナンス性に深刻な影響を与える可能性があります.
    そのため、最も良い方法は、内蔵されたプロトタイプに属性を追加しないことです.1、未来のECMAScriptバージョンまたはJavaScriptの具体的な実現は、この機能を統一的な内蔵方法とすることができる場合を除きます.2、カスタムの属性や方法が存在しないことを確認した場合.あるいは異なるブラウザや同じブラウザの異なるバージョンを統一するための互換性がある場合は、存在するかどうかを確認することが前提です.3、文書の記録とチームとのコミュニケーションがはっきりしている.
    上のシーンに確実に会ったら、こうしてもいいです.
    if(typeof Object.prototype.myMethod !== 'function'){
        Object.prototype.myMethod = function () {
            // implementation
        }
    }
    
      
    四、スイッチモード
    switchと言えば、多くの新米はif-elseの性能がいいか、それともswitchの性能がいいかを悩んでいます.まず、具体的な場面を捨てて性能を語るというのは、痴漢です.次に、スイッチはc++という言語の中で、性能は確かに少しいいです.しかし、JavaScriptの中では、ほとんど区別がない上に、switchは意外な問題を引き起こす可能性がありますので、if-elseを使うことを提案します.
    もしあなたがSwitchがより良い選択だと確信したら、このようにしてもいいです.
    var inspect_me = 0,
        result = '';
    switch (inspect) {
    case 0:
        result = 'zero';
        break;
    case 1:
        result = 'one';
        break;
    default:
        result = 'unknow';
        break;
    }
    
    通常、フォーマットはこうです.
  • caseごとにswitchを縦に並べる(括弧の締め方は例外).
  • 各caseにコードを用いてインデントする.
  • case文の末尾に明確なbreak文がある.
  • fall-throughsの使用を避ける(つまり、意図的にbreak文を使わずにプログラムを順番に下に進めるようにする).fall-throughsを使用したい場合は、コードの中でfall-throughsを使用することが最善の方法であると確信してください.これは他の人がこのコードを読んでいる時には間違いだと思います.
  • default文でswitchの終了とする:上記のシーンが一致しない場合、デフォルトの結果を与える.
  •  
    五、隠蔽タイプの転換は避ける
    あなたのプログラムで使用しないでください.使用してください.JavaScriptは比較文を使う時に暗黙的なタイプの変換を行うからです.変換するシーンはあなたが知っているよりずっと多いかもしれません.
     
    六、evalの使用を避ける()
    エヴァは悪魔で、あなたの夢を叶えて、魂を奪うことができます.ですから、あなたのコードの中でeval()を使わないようにしてください.
    この関数は、任意の文字列をJavaScriptコードとして実行できます.議論が必要なコードがあらかじめコンパイルされている場合(ダイナミック運転ではなく決定されます)は、evalを使用する理由がありません.コードが実行時に動的に生成される場合、eval()の代わりに、他のより良い方法があります.たとえば:
    //    
    var property = 'name';
    alert(eval("obj." + property));
    
    //      
    alert(obj[property])
    eval()を使用すると、一部のセキュリティ上の潜在的な危険も含まれています.このようにすると、改竄されたコード(例えば、ネットワークからのコード)が実行される可能性があります.
    もう一つ覚えておきたいのは.setInterval()やsetTimeout()やfunction()などの構造関数によってパラメータが伝達され、ほとんどの場合、eval()のような隠れた危険が生じるので、これらの関数の使用は避けるべきです.舞台裏では、JavaScriptはまだプログラムコードで伝達された文字列を評価し実行しなければならない.
    //    
    setTimeout('myFunc()',1000);
    setTimeout('myFunc(1,2,3)',1000);
    
    //      
    setTimeout(myFunc,1000);
    setTimeout(function() {
        myFunc()
    },1000)
    new Function()を使用するとeval()を使用するのと比較的に似ていますので、この関数の使用にも十分注意が必要です.この関数は強力な機能の関数ですが、通常は誤用されやすいです.eval()が必要であれば、new Function()を使って代用することも考えられます.このようにする潜在的な利点は、new Function()のコードが局所関数空間で実行されるため、コード内の任意のvar定義変数が自動的に大域変数になりません.もう一つは自動的にグローバル変数にならないようにする方法は、eval()呼び出しをリアルタイム関数にパッケージ化することである.
    下のコードを見てください.ここではunだけがグローバル変数です.名前空間に影響を与えます.
    console.log(typeof un);
    console.log(typeof deux);
    console.log(typeof trois);
    
    var jsstring = "var un = 1; console.log(un)";
    eval(jsstring);
    
    jsstring = "var deux = 2; console.log(deux)";
    new Function(jsstring)();
    
    jsstring = "var trois = 3; console.log(trois)";
    (function() {
        eval(jsstring);
    }());
    
    console.log(typeof un);
    console.log(typeof deux);
    console.log(typeof trois);
    もう一つのnew Function()とeval()の違いは、eval()が作用するドメインチェーンに影響しますが、Functionは一つの砂箱のようなものが多いです.どこでFunctionを実行しても、グローバルスコープだけを見ることができます.したがって、局所変数に対する影響は小さい.以下の例では、eval()は、その外部作用領域の変数にアクセスして修正することができますが、Functionはできません.
    (function () {
        var local = 1;
        eval("local = 3;console.log(local)");
        console.log(local);
    }());
    
    (function() {
        var local = 1;
        Function("console.log(typeof local);")();
    }())
     
    七、パーrseInt()を使った数値約束
     paress Int()を使用することで、1つの文字列から数値を取得することができます.この関数の2番目のパラメータは禁止パラメータで、通常はこのパラメータを無視できますが、しないほうがいいです.解析した文字列が0で始まると、エラーが発生します.例えば、処理日付の一部だけがフィールドに入力されます.ECMAScript 3では、0から始まる文字列は8進数として扱われますが、ECMAScript 5で変更されました.不一致と予想される結果を避けるために、毎回具体的な進数パラメータを指定してください.
    var month = '06',
        year = '09';
    month = parseInt(month,10);
    year = parseInt(year,10);
    console.log(month,year);
    もう一つの文字列を数値に変換する方法は、
    Number('01');
    この方法は通常、パーrseInt()よりもはるかに速い.その名前のように、パーrseInt()は簡単な変換ではなく解析であるからである.しかし、もし「08 hello」が数値に戻ることを望むなら、parseInt()以外の方法は失敗してNaNに戻ります.
    この内容は比較的多いが、実際の仕事には十分価値がある.次のページでは、名前を付ける、括弧を打つ、スペースを字下げするなどの規則や制約について説明します.