(B)JavaScriptの変数、スコープとメモリの問題

入門

ECMA-262の定義では、JavaScriptの変数は非常に異なる言語や他の変数です。JavaScript変数がされているのでルーズ変数の値データ型は、スクリプト可能ライフサイクルを変更するにはいくつかの方法で、これは楽しさと強力です、が、また、簡単に特徴的な問題が、はるかに複雑の実際の程度にそれよりもはるかに。

値型と参照の基本タイプ

ECMAスクリプトは、異なるデータ型の二つの可変値:(含むことができ、ベース型参照型の

  • 基本タイプ:シンプルなデータセグメント(未定義、ヌル、ブール、ナンバー、文字列)を使用すると、変数に格納された実際の値を操作することができますので、この値は、アクセスの5種類に基づいています。
  • 参照タイプ:(値の複数の形成された物体オブジェクト)、値型のメモリに記憶された基準オブジェクト。他の言語とは異なり、JavaScriptが直接許可されていませんメモリ操作オブジェクトを操作でオブジェクトが操作に実際にあるオブジェクト参照ではなく実際のオブジェクトよりも、。基準値によってアクセスするとき、基準タイプ。

値が変数に割り当てられた場合、パーサはこの値が決定しなければならない基本的な型または参照型

ヒント:多くの言語は、オブジェクトの文字列表現の形で、それが参照型と考えられています。この伝統を放棄ECMAScrip。

動的プロパティ

基本タイプ及び種類の参照と同様に定義されるが、後の操作の実行可能な値の異なるタイプの作成した変数に格納された値が異なっていてもよいです。

このような2を次のように:

  1. 基本タイプ

    // 基本类型无法添加属性,尽管这样做不会导致任何错误。
    var name = "Nicholas";
    name.age = 27;
    alert(name.age); // undefined
  2. 参照型

    // 但引用类型却可以动态的添加属性,如果对象不销毁或属性不被删除,则这个属性一直存在。
    var person = new Object();
    person.name = "Nicholas";
    alert(person.name);

変数の値をコピーします。

  • 様々な方法のストレージに加えて、より可変別の変数にコピーベース・タイプ値基準値型異なるがあります。

基本タイプの値がコピー起こります。

var num1 = 5;    // num1 在栈中开辟空间存值 5
var num2 = num1; // num2 在栈中开辟空间存值(从 num1 空间复制过来的 5)
// 两个变量的空间都是独立存在的并没有任何关联。
// 相当于 num1开一间房,num2开一间房,num2 叫了一份和 num1 一样的外卖。

参照型の値がコピー起こります。

var obj1 = new Object(); // obj1 在栈中开辟空间存对象的地址,对象存放在堆内存中。
var obj2 = obj1;         // obj2 在栈中开辟空间存 obj1保存的地址,可操作 obj1 的对象。
obj1.name = "Nicholas";  
alert(obj2.name); // Nicholas
// 当 obj2 复制 obj1 变量时,两个变量同时指向一个 对象,相当于两家人有一个共同的仓库。

パラメータを渡します

  • ECMAScriptの機能は、すべてのパラメータは、関数に値のコピーで外部パラメータの関数である値によって渡されます。

    機能受信パラメータ基本パラメータときに:

    function addTen(num) {
      num += 10;
      return num;
    }
    
    var count = 20;
    var result = addTen(count);
    alert(count); // 20,没有变化
    alert(result);// 30
    
    // 简单理解:result 叫了addTen函数的参数 叫了一份 count一样的外卖,加了特技,返回给他
    // 而 addTen函数并没有修改 count 所以没任何变化

    関数パラメータ受信型参照のとき:

    function setName(obj){
      obj.name = "Nicholas";
      obj = new Object();
      obj.name = "Greg";
    }
    var person = new Object();
    setName(person);
    alert(person.name); // "Nicholas"
    /*
      可以看上面的 复制引用变量值,自行领会。 
      我发现我竟然无法言语解释。
    */

検出タイプ

変数は、オペレータが最高のツールですが、変数がオブジェクトまたはnullの場合、typeofのObjectオブジェクトが返されtyepof、基本データ型でないかを検出します。

検出の基本的なタイプは、非常に有能なアシスタントが、オペレータ用のこのタイプの検出にはほとんど基準値であるが。しかし、我々は、オブジェクトの型が値であるかを知りたいです。ECMAScriptのに提供することを目的にinstanceof演算子を

result = variable instanceof constructor
// 如果变量是给定引用类型
alert(person instanceof Object);  // 变量 person  是 Object 吗?
alert(colors instanceof Array);   // 变量 colors  是 Array  吗?
alert(pattern instanceof RegExp); // 变量 pattern 是 RegExp 吗?

規則によると、すべての参照型の値は、オブジェクトのインスタンスです。..

  • いつ、参照タイプ、常にinstanceofは検出オブジェクトがtrueを返します
  • instanceofは常にfalseを返し、プリミティブ値を検出

スコープと実行環境

実行環境(実行コンテキスト)と呼ばれることもあり、環境、JavaScriptが最も重要な概念です。実行環境は、定義変数関数がに資格を与えているへのアクセス、他のデータ、自分の行動を決定し、。各実行環境は、関連付けられた変数オブジェクト(可変オブジェクト)を、環境に定義されているすべての変数と関数は、このオブジェクトに格納されています。それはオブジェクトに書き込みの時間にアクセスすることはできませんが、データを処理している間、パーサーは、バックグラウンドでそれを使用しますが。

var color = "blue";
function changeColor(){
  var anotherColor = "red";
  function swapColors(){
    var tempColor = anotherColor;
    anotherColor = color;
    color = tempColor;
    
    // 这里可以访问 color、anotherColor 和 tempColor
  }
  
  // 这里可以访问 color 和 anotherColor 但不能访问 tempColor
  swapColors();
}

// 这里只能访问 color
changeColor();
  • 内部環境は、スコープチェーンを介して外部環境のすべてにアクセスすることができしかし、外部環境は、任意の変数や関数の内部環境にアクセスすることはできません。
  • 環境との間のリンクは、整然とした直線的です。
  • それぞれの環境には、クエリ変数や関数にスコープチェーンを検索することができます。
  • しかし、どのような環境ができていないスコープチェーンの実行環境をダウン検索して、別の中へ。
  • 関数のパラメータも、変数として扱われ、同じ実行環境でのアクセスルールと他の変数そう。

スコープチェーンを拡張

実行環境:(の2種類があり、グローバルローカル(機能))は、しかし、スコープチェーンを拡張する他の方法があります。

例えば、いくつかのステートメントが一時的スコープチェーンの前に可変オブジェクトを増大させることができるコードが実行された後、可変オブジェクトが削除されます。

この現象が発生する2つのケースがあります。

// 当执行流进入下列任何一个语句时,作用域就会得到加长
try-catch 语句的 catch 块;
with 语句

どちらのステートメントは、スコープのフロントエンドで変数オブジェクトを追加します。

  • with文の場合は、スコープチェーンに指定されたオブジェクトを追加します。

  • catchステートメントには、エラーオブジェクトがスローされるように宣言されている含まれている新しい変数オブジェクトを作成します。

// 例如
function buildUrl(){
  var qs = "?debug=true";

  with(location){
    var url = href + qs;
  }

  return url;
}
  1. ステートメントは、オブジェクトの位置である受け付けると、従ってオブジェクト変数は、位置オブジェクトのすべての属性およびメソッドを含み、このオブジェクトが変数スコープチェーンのフロントエンドに追加されます。
  2. buildURL()関数は、変数適量を定義します。参照変数を持つ文は(実際の引用がLOCATION.HREFある)てhref場合は、現在の実行環境における変数のオブジェクトで見つけることができます。
  3. 参照変数のQSは、変数buildUrl()で定義されている参照していることを、変数に対し可変オブジェクト関数環境がある場合。
  4. 内部の文と同じように、URLをURLという名前の変数を定義して、関数の実行環境の一部となった、それは関数の値として返すことができます。

いいえブロックレベルのスコープありません

  1. JavaScriptはブロックレベルのスコープはしばしば理解の混乱につながるはありません。他の言語ではCは、括弧で囲まれ、コードブロックは条件に応じて変数を定義するためにどの支持体、(ECMAスクリプトの言葉を使用する場合、独自の実行環境である)、それ自身の範囲を有しています。
// 例如,下面代码在 JavaScript 中并不会得到想象中的结构:
if (true) {
  var color = "blue";
}

alert(color); // "blue"
在 if 语句中定义了变量 color ,如果在 C、C++或Java中,color 会在 if 语句执行完毕后被销毁。

但在JavaScript中,if 语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境中)。
  1. 特に、この違いのために使用した文には、例えば、心に留めておきます:
for (var i=0;i < 10; i++){
  doSomething(i);
}
alert(i); // 10

ブロックレベルの範囲のために、文は、ループの外部環境中に存在する定義された変数の発現のための変数を初期化します。

JavaScriptのために、for文で作成された変数は、私も、実行のためのサイクルの終了後に、それはまだ外側のループの実行環境に存在しています。

  1. 宣言変数

    変数でのvar宣言は、自動的に最新の環境に追加されます関数内、最も近い環境での関数であるローカル環境、最も近い環境との声明の中で、環境の関数です。あなたは、変数を初期化するためにvarステートメントを使用しない場合、変数は自動的に、地球環境に追加されます。

    function add(num1, num2){
     var sum = num1 + num2; // sum添加到函数的局部环境中
     return sum;
    }
    var result = add(10, 20); //30
    alert(sum);  // 由于 sum 不是有效的变量,因此会导致错误。

    結果は、関数から返されたが、和という名前のローカル変数を定義()上記機能コードを追加し、しかし、変数sumにアクセスできないように機能するには、外部です。場合は省略し、本例ではvarキーワード、そして時に追加機能の実装後SUMは、アクセスすることができます

    function add(num1, num2){
     sum = num1 + num2; // sum添加到全局环境中
     return sum;
    }
    var result = add(10, 20); //30
    alert(sum);               //30

    上記の変数の和の例としては、初期化されるときに使用していないするvar inキーワードこのように、仕上げアドオン()の呼び出しでは、地球環境に追加変数の和は存在し続けます。機能が終了した場合でも、あなたはまだそれの後ろにコードにアクセスすることができます。

  2. クエリの識別子

    ために環境に読むこと、書き込み識別子を参照するときに、必要があります検索することを決定するためにどのような実際の識別子を表します

    指定された名前に一致する問い合わせ識別子アップ段階、スコープチェーンの正面から処理を開始し検索。ローカル環境が識別子を見つけるためにした場合、検索処理は、変数準備ができて、停止します。変数名がローカル環境に見つからない場合、検索はスコープチェーンをアップし続けています。検索プロセスは、地球環境の変数オブジェクトに遡るされています。あなたが地球環境にこの識別子が見つからなかった場合は、その変数が宣言されていないことを意味します。

    // 通过下面的示例,可以理解标识符的过程
    var color = "blue";
    
    function getColor(){
     return color;
    }
    
    alert(getColor()); // "blue"

    このクエリプロセスは、地元のローカル環境変数を見つけ、近接の原理を利用し、地球環境を見つけるために、それを見つけることができませんでした、あなたの未定義では見られません。

    // 通过下面的示例,可以理解标识符的过程
    var color = "blue";
    
    function getColor(){
      var color = "red";
     return color;
    }
    
    alert(getColor()); // "red"

ヒント:変数のクエリは価格がないわけではありません。明らかに、グローバル変数よりローカル変数速く、何の上方検索スコープチェーンがありませんので。JavaScriptエンジンは、クエリ識別子を最適化するには良い仕事をしたので、私は将来的にこの差は無視できることを恐れています。

ガーベジコレクション

JavaScriptが持つ自動ガベージコレクション機構、され、実行環境を管理するための責任を負うことになります、コード実行のプロセスのメモリ使用量を

CおよびC ++言語のクラスは、開発者の基本的なタスクは、手動で多くの問題の根本的な原因であるメモリ使用量を追跡することです。JavaScriptプログラムを書くとき、開発者は、もはやメモリ、必要なメモリの割り当てと自動管理の無駄なメモリ回復完全な実現を使用することを心配する必要はありません。

原則:原則は使用し続け、もはやこれらの変数を識別するための非常に簡単なJavaScriptのガベージコレクション機構であり、その後、メモリを解放することです。この目的のために、ガベージコレクタは、定期的にこの操作を行う間隔(又は、所定の収集時間で実行される)固定された時間に従います。

簡単分析:ローカル変数は、関数の実行中にのみ存在するローカル変数の正常なアサーション周期関数、プロセスは、それらの値を格納するスタック(またはヒープ)メモリ上の適切な空間に割り当てられたローカル変数になります。次に、関数の実行が終了するまで関数内でこれらの変数を使用しています。この場合は、必要が、彼らは将来の使用のためにメモリを解放できるように、ローカル変数を存在しません。この場合、そこに存在している必要な変数かどうかを判断するのは簡単です。すべてではない例は、結論に達することは簡単です。ガベージコレクタは無用の変数は便利な変数、もはや有益なその占有メモリの将来の回復のためのマーカーでマークされた変数のための追跡する必要があります。不要な変数を識別するための戦略は、実装固有ますが、ブラウザの実現に特異的であってもよく、通常は2つの戦略があります。

クリアラベル

最も一般的に使用されるJavaScriptのガベージコレクションは、クリア(マークアンドスイープ)標識されています。

  • 環境への変数(例えば、変数は関数内で宣言された)、この変数は次のようにマークされている場合は、「環境に。」

  • 環境変数を残す場合は、「環境を残す。」とマークされています

まず、ときガベージコレクタは、メモリに保存されているすべての変数がマーカー(マーカーはどのような方法で使用することができる)でマークされて実行されます。

その後、それが削除されます、環境変数参照変数環境変数ラベルを。そして、それを再度した後、変数でフラグが付けられてとして扱われる変数を削除して調製した環境変数がこれらの変数にアクセスすることができなかったので、。

最後に、ガベージコレクタのメモリは、クリーンアップを完了するための破壊、これらのタグ付きの値を、それらが占めるメモリ領域を解放。

参照カウント

呼ばれる別のあまり一般的でガベージコレクションの戦略参照カウント(参照カウント)。基準カウント値のそれぞれを回数を意味して実績を参照されます。

  1. 値は変数タイプに割り当てられている場合、可変基準引用を宣言する場合、この値は1です。
  2. 値は同じ参照番号が別の変数に割り当てられている場合、値がインクリメントされます。
  3. あなたは変数参照の値が含まれ、別の値を加えた場合は逆に、その後、基準値が1ずつ減少しました。この値は、この値にアクセスする方法は、その後、ゼロの引用になっていないし、次にメモリ空間まで回復させることができるとき。
  4. 次回は、ガベージコレクタの実行時にこのように、それは占有メモリの値が0にそれらの引用を解放します。

ネットスケープナビゲーター3.0は、使用する最初のものです参照カウント戦略ブラウザが、それはすぐに深刻な問題が発生しました:循環参照を円形の参照オブジェクトAがオブジェクトBへのポインタを含む、オブジェクトBは、基準オブジェクトへのポインタを含みます。

// 循环引用例子:
function problem(){
    var objectA = new Object();
    var objectB = new Object();
    
    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

この目的を達成するために、Netscapeはそのガベージコレクションメカニズムを達成するための明確なラベルの賛成でナビゲーター4.0参照でカウントをあきらめました。それは、最後までトラブルに参照カウントをリードすることができませんでした。

  1. 私たちは、IEがオブジェクトの一部であるネイティブJavaScriptオブジェクトではありません、知っています。

  2. ガベージコレクションは、参照カウント戦略を使用してCOMオブジェクトであるが、例えばBOMおよびDOMオブジェクトは、COMとC ++(コンポーネントオブジェクトモデル、コンポーネントオブジェクトモデル)は、実施の形態でオブジェクトれます。

  3. そのため、IEのJavaScriptエンジンは、参照カウントの戦略に基づいてマークを達成するための明確な戦略を使用することですが、まだアクセスJavaScriptのCOMオブジェクト場合でも。単にIEのCOMオブジェクトに関与していることを、つけ、循環参照が存在します。

    次の例を参照してください。

    // 当出现循环引用,即使例子中的 DOM 从页面中移除,它也永远不会被回收。
    var element = document.getElementById('some_element');
    var myObject = new Object();
    myObject.element = element;
    element.someObject = myObject;
    
    // 为了避免循环引用问题,将变量设置为 null 意味着切断了变量与它此前引用的值之间的连接。
    myObject.element = null;
    element.someObject = null;
  4. 上記課題を解決するために、IE9 BOMおよびDOMオブジェクトは、JavaScriptがオブジェクトの本当の意味になっています。このように、ガベージコレクションのアルゴリズムリードの2種類の共存を避けるために、だけでなく、一般的なメモリリークを排除します。

パフォーマンスの問題

ガベージコレクションが定期的に実行され、変数に割り当てられたメモリの量が目的であれば、その後、復旧作業負荷が非常に大きいです。

時間間隔ガベージコレクションが非常に重要な問題であるかを決定するために、あなたにこのケースをかじります。彼は、ガベージコレクタがIEのパフォーマンスの問題を連想させるため、厄介つ以上の時間を、実行するように言いました。

  • IEのガベージコレクションは、メモリ割り当て、特に変数256である点、4096個のオブジェクト(又は配列)とリテラル配列要素(スロット)または64キロバイトの文字列に応じて実行されています。
  • 臨界値上記のいずれかを達成するため、ガベージコレクタが実行されます。この実装での問題は、スクリプトは非常に多くの変数が含まれている場合、スクリプトはそのライフサイクルで非常に多くの変数を維持する必要があり、ということです。そうすることで、ガベージコレクタが頻繁に実行する必要があります。その結果、生じた深刻なパフォーマンスの問題は、IE7は、他のガーベッジコレクションルーチンを書き換える促しました。
  • IE7のリリースでは、JavaScriptエンジンのガーベジコレクションルーチンは仕事を変更:リテラルおよび(または)トリガー変数の代入ガベージコレクション、配列要素の臨界値が調整されている動的に修正しました。IE7閾値は、初期IE6と等しいです。メモリ割り当てルーチンのガベージコレクションが15%未満を回収する場合は、変数、リテラル、および(または)スレッシュホールドアレイ要素が倍増します。ルーチン85%のメモリ割り当てを回収する場合、種々の閾値がデフォルト値にリセット。この一見単純な調整は、大幅にページがJavaScriptの実行を大量に含まれているIEの性能を向上させます。

ヒント:実際には、いくつかのブラウザでは、ガベージコレクションプロセスを引き起こす可能性が、我々はそうするリーダーをお勧めしません。IEでは、直ちにwindow.CollectGarbage()メソッドが実行ガベージコレクションを呼び出します。Opera7以降では、コールwindow.opera.collect()ガベージコレクションのルーチンを開始します。

メモリ管理

プログラミングのガベージコレクションで使用する言語、開発者は、一般的にメモリ管理の操作上の問題を持っていません。しかし、JavaScriptのメモリ管理やごみの収集中に直面する問題はまだ少し異なっています。

最も重要な問題は、Webブラウザに割り当てられた使用可能なメモリの量が通常よりも少ないデスクトップアプリケーションに割り当てられています。そうすることの主な目的は、目的は、JavaScriptのウェブは、すべてのシステムメモリを使い果たし実行阻止することであると、システムがクラッシュすることが、セキュリティ上の考慮事項です。

メモリの制限は、変数に割り当てられたメモリに影響を与えるだけでなく、コールスタックと同時に実行することができます1つのスレッドで文の数に影響します。

そのため、ページのより良いパフォーマンスをすることができ、最小限のメモリフットプリントを確保します。コードの実装が必要なデータのみを保存するためのものです最適化のメモリ使用量に最善の方法、。データ一旦好ましくはヌルへの参照を解放するためにその値を設定することにより、もはや有用ではない-この手順が呼び出され、接触基準(間接参照)。

このアプローチは、ほとんどの属性グローバル変数やオブジェクトに適用されます。彼らは例えば、参照実行環境を離れるときに、ローカル変数は自動的に接触させます。

function createPerson(name){
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
}

var globalPerson = createPerson("nicholas");
// 手工解除 globalPerson 的引用
globalPerson = null;
  • 関数がその実行環境を完了した後に出るとき、私たちはそれを達するために、明示的に参照する必要はありません。

  • しかし、グローバル変数は、あなたたちは、コードの最後の行、上記の例の目的であるそれのためのリファレンスマニュアル、と接触していないときにそれを使用する必要があります。
  • しかし、基準値のリフティングは、占有メモリの値の自動回復を意味するものではありません。本当の役割を持ち上げるためには、それが回復したときに、ガベージコレクタの次の実行のための実行環境から基準値を作ることです。

概要

  1. JavaScriptの変数には、2つのタイプを保存するために使用することができます。
  • 基本タイプ(未定義、ヌル、ブール値、数値、文字列)
  • 参照型(オブジェクト)
  1. プリミティブ値種類の基準値以下の特徴を含みます。
  • スタックはメモリに格納されているように、固定サイズの値の基本的なタイプは、メモリ内のスペースを占有します。
  • 別の変数に1つの変数からプリミティブ値をコピーし、その値のコピーを作成します。
  • 値は、ヒープメモリに格納された参照型のオブジェクトです。
  • ないオブジェクト変数の値は、実際に自分自身を含む参照タイプが含まれているが、オブジェクトへのポインタ。
  • 別のタイプの可変基準変数値からコピーされ、ポインタは実際にコピーされ、最終的な二つの変数は、同じ対象を指しています。
  • 使用することができ、オペレータのタイプTYPEOF実質的であり、場合値instanceof演算子参照の種類を決定するために使用される値を決定します
  1. (プリミティブ型と参照型を含む)全ての変数は、実行環境の間で(また、範囲としても知られる)、実行環境に存在する変数のライフサイクルを決定し、その変数にアクセスすることができるコードの一部。
    以下は、いくつかの点に要約実行環境であります

    • 実行環境グローバル実行環境(また、地球環境としても知られる)と点の関数実行環境。

    • あなたは新しい実行環境に入るたびに、変数や関数を検索するために使用されるスコープチェーンを作成します。

    • ローカル環境機能は、変数、関数のスコープへのアクセスを持っているだけでなく、彼らの(親)環境だけでなく、地球環境にアクセスする権利が含まれていないだけ。

    • あなただけの地球環境に定義されたグローバル環境変数や関数にアクセスすることができますが、ローカル環境に直接任意のデータにアクセスすることはできません。

    • 実行環境変数は、それがメモリを解放すべき時に決定するのに役立ちます。

  2. JavaScriptは自動ガベージコレクション機構を使用したプログラミング言語である、開発者は、メモリの割り当てと回復の問題を心配する必要はありません。

    次の要約を作成するには、次のJavaScriptガベージコレクションルーチン:

    • 範囲外の値が自動的にリサイクル可能とマークされますので、ガベージコレクション中に削除されます。
    • 「クリアマークが」主流のガベージコレクションアルゴリズムで、このアルゴリズムの考え方は、現在値のプラスマークを使用して、そのメモリを回復されていません。
    • このアルゴリズムの別ガベージコレクションのアルゴリズムである「参照カウント」のアイデアは、参照されたすべての値の数を追跡することです。JavaScriptエンジンは、現在、このアルゴリズムを使用していない。しかし、アクセスする非ネイティブJavaScriptがIEで(例えばDOMオブジェクトとして)オブジェクト際に、このアルゴリズムはまだ問題の原因となります。
    • 循環参照コード現象がある場合は、「参照カウント」アルゴリズムは、問題を引き起こす可能性があります。
    • リフト変数の参照循環参照の現象を排除するために役立つだけでなく、ガベージコレクションのために良いだけではなく。メモリの効果的な回復を確保するためには、もはや使用されているグローバルオブジェクト、参照グローバルオブジェクトのプロパティと循環参照の変数を解除しなければなりません。

おすすめ

転載: www.cnblogs.com/forface/p/12430347.html