「JavaScript高級プログラム設計」メモ:変数、作用領域とメモリ問題(四)


基本タイプと参照タイプの値
ECMAScript変数は、2つの異なるデータタイプの値を含むことができます.基本タイプの値と参照タイプの値です.基本タイプの値は単純なデータセグメントを意味し、参照タイプの値は複数の値からなる可能性のあるオブジェクトを意味します.
ダイナミックな属性
var person = new Object();
person.name = "Nicholas";
alert(person.name); // Nicholas
var name = "Nicholas";
name.age = 27;
alert(name.age); // undefined
この説明は、参照タイプの値に属性を動的に追加するだけです.
変数値をコピー
var num1 = 5;
var num2 = num1;
num 1に保存されている値は5です.num 1の値を用いてnum 2を初期化すると、num 2にも値5が保存されていますが、num 2の5とnum 1の5は完全に独立しています.この値はnum 1の5のコピーにすぎません.
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); // Nicholas
変数obj 1は、オブジェクトの新しいインスタンスを保存します.そして、この値はObj 2にコピーされる.つまり、obj 1とobj 2は同じ対象を指しています.このように、Obj 1にname属性を追加すると、Obj 2を介してこの属性にアクセスすることができる.
転送パラメータ
function addTen(num){
    num +=10;
    return num;
}

var count = 20;
var result = addTen(count);
alert(count); // 20,     
alert(result); //30
例:
function setName(obj){
        obj.name = "Nicholas";
    }
    
    var person = new Object();
    setName(person);
    alert(person.name); // "Nicholas"
  
例:
function setName(obj){
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); // "Nicholas"
personが参照によって伝達される場合、personは、自動的に、そのname属性値が「Greg」であることを指す新しいオブジェクトに変更される.
実行環境とスコープ
var color = "blue";
    function changeColor(){
        if(color == 'blue'){
             color = 'red';
        }else{
            color = 'blue';
        }
    }
    changeColor();
    alert('color is now' + color); //red
ごみの収集
ごみの回収
javascriptはゴミ回収の仕組みを持っています.つまり、実行環境はコードの実行中に使うメモリを管理します.残りの多くは,関数における局所変数の通常のライフサイクルを解析した.ローカル変数は関数実行中にのみ存在します.このプロセスでは、ローカル変数は、スタック(またはスタック)メモリ上にそれぞれの空間を割り当てて、彼らの値を記憶する.関数が終わるまで、関数にこれらの変数を使います.この時、局部変数は存在する必要がないので、彼らが使っているメモリを解放します.現在、各ブラウザで使用されているゴミの回収には2つの方法があります.マーククリア、参照カウント.
タグクリア
これはjavascriptの中で一番よく使われているゴミの回収方法です.変数が実行環境に入ると、この変数は「環境に入る」とマークされます.論理的には、環境に入る変数によって占有されたメモリは永遠に解放されません.実行フローが相応の環境に入ると、彼らを使うことができるからです.変数が環境から離れると、それを環境から離れるというマークが付けられます.
ゴミ収集器は実行時にメモリに格納されているすべての変数にマークを付けます.次に、環境内の変数と環境内の変数によって参照されるタグを削除します.この後にマークを付けた変数は、環境内の変数がこれらの変数にアクセスできなくなっているため、削除を準備している変数と見なされます.最後に.ごみ収集器はメモリの消去作業を完了し、マーク付きの値を廃棄し、彼らが使っているメモリ空間を回収します.
参照数
もう一つの一般的ではないゴミ回収戦略は参照数です.参照カウントとは、各値が参照された回数を追跡記録することを意味します.変数を宣言して参照型を変数に割り当てた場合、この値の参照回数は1です.逆に、この値に対して参照する変数が含まれている場合は、この値の参照回数は1を減算します.この参照回数が0になると、この値にもうアクセスできないということですので、メモリの容量を元に戻すことができます.このように、ゴミ収集器は次の運転時に、それらの引用回数が0の値が占めているメモリを解放します.
しかし、この方法で問題があります.コードを見てみます.
function problem(){
     var objA = new Object();
     var objB = new Object();
     objA.someOtherObject  = objB;
     objB.anotherObject = objA;
}
この例では、ObjAとObjBはそれぞれの属性を介して相互参照される.つまり、この二つのオブジェクトの引用回数は全部2です.参照カウントを採用するポリシーでは、関数が実行された後、この2つのオブジェクトは機能領域から離れているので、関数が実行された後も、ObjAとObjBは引き続き存在します.彼らの参照回数は永遠に0ではないからです.このような相互参照は、大量に存在するとメモリが大量に漏れます.
私たちは、IEの一部のオブジェクトが元のJavaScriptオブジェクトではないことを知っています.例えば、そのBOMとDOMの対象は、C++を使用してCOM(Component Object Model、コンポーネントオブジェクト)オブジェクトとして実現され、COMオブジェクトのゴミ回収器は参照カウントを採用するポリシーである.したがって、IEのJavascriptエンジンがマーククリアのポリシーを使用して実装されても、JavaScriptアクセスのCOMオブジェクトは依然として参照カウントに基づくポリシーである.はっきり言って、IEの中でCOMの対象に関連するのでさえすれば、循環参照の問題が存在します.この簡単な例を見てください.
var element = document.getElementById("some_element");
var myObj = new Object();
myObj.element = element;
element.someObject = myObj;
上記の例では、DOM要素と元のJavaScriptオブジェクト(myObj)との間に循環参照が確立されている.ここで、変数myObjはelementという属性がelementを指しています.変数elementにはsomeObjectという属性があります.myObjに戻ります.循環参照のため、たとえ例のDOMをページから削除してもメモリは永遠に回収されません.
でも、上記の問題も解決できないわけではないです.マニュアルで彼らの循環参照を切断できます.
myObj.element = null;
element.someObject = null;
メモリ管理
JavaScriptを使ってプログラミングして、私達は普通はすべてメモリの回収の問題を管理する必要がなくて、もし高いレベルのコードを書き出したいならばそれとも少し問題があります.一つの主要な問題は、WEBブラウザに割り当てられた利用可能メモリは、通常デスクトップアプリケーションに割り当てられたものより少ないです.このようにする目的は主に安全面の考慮によるもので、JavaScriptを実行するウェブページがシステムメモリ全体を使い果たしてシステムが崩壊することを防止するのが目的です.メモリ制限問題は、変数にメモリを割り当てるだけでなく、スタックの呼び出しや、スレッド内で同時に実行できるステートメントの数にも影響します.
したがって、最小のメモリを占有することで、ページがより良い性能を得ることができることを保証する.メモリ占有を最適化する最適な方法は、実行中のコードが必要なデータだけを保存することです.データが有用でない場合は、その値をnullに設定することによって参照を解放することが望ましい.この方法はほとんどの大域変数と局所変数の属性に適しています.ローカル変数は、彼らが実行環境から離れると自動的に参照が解除されます.コードを見てみます.
 function createPerson(name){
       var localPerson = new Object();
       localPerson.name = name;
       return localPerson;
}
var globalPerson = createPerson("Tracy");
globalPerson = null; //      
この例では、変数global Personは、createPerson関数の戻り値を取得している.createPerson関数の内部では、オブジェクトを作成し、その値を局所変数local Personに割り当て、さらにローカル変数にnameという属性を追加しました.最後に、この関数を呼び出すと、local Personは関数値として戻り、global Personに割り当てられます.local PersonはcreatePerson関数の実行が終わった後に実行環境を離れましたので、私達が表示する必要はなくて、彼らのために引用を解除します.しかし、global Personにとっては、私達がそれを使わない時にマニュアルで彼のために引用を解除する必要があります.
ただし、1つの値の参照を解除することは、メモリを自動的に回収することを意味しない.参照解除の真の役割は、値を実行環境から逸脱させ、ゴミ収集器を次の運転時に回収することです.