簡単な答え: の値がstr
どこからも参照されていない場合 (およびstr
それ自体が から参照されていないrestofprogram
場合)、 が戻るとすぐに到達不能になりfunction (str) { ... }
ます。
詳細: V8 コンパイラは、実際のローカル変数を、 withステートメントまたは呼び出しによってシャドウされる、クロージャによってキャプチャされた、いわゆるコンテキスト変数と区別します。 eval
ローカル変数はスタック上に存在し、関数の実行が完了するとすぐに消えます。
コンテキスト変数は、ヒープに割り当てられたコンテキスト構造に存在します。コンテキスト構造が死ぬと、それらは消えます。ここで注意すべき重要なことは、同じスコープのコンテキスト変数は同じ構造に存在するということです。サンプルコードで説明しましょう:
function outer () {
var x; // real local variable
var y; // context variable, referenced by inner1
var z; // context variable, referenced by inner2
function inner1 () {
// references context
use(y);
}
function inner2 () {
// references context
use(z);
}
function inner3 () { /* I am empty but I still capture context implicitly */ }
return [inner1, inner2, inner3];
}
この例では、 variable は返さx
れるとすぐに消えouter
ます but 変数y
とは、との両方が死ぬz
場合にのみ消えます。これは、とが同じコンテキスト構造に割り当てられており、3 つのクロージャーすべてがこのコンテキスト構造を暗黙的に参照している (明示的に使用していない場合でも) ために発生します。 inner1
inner2
inner3
y
z
inner3
with -statement、try/catch -statement の使用を開始すると、状況はさらに複雑になります。V8 では、 catch 句または global 内に暗黙的なwitheval
-statement が含まれています。
function complication () {
var x; // context variable
function inner () { /* I am empty but I still capture context implicitly */ }
try { } catch (e) { /* contains implicit with-statement */ }
return inner;
}
この例では死亡x
時にのみ消えます。inner
なぜなら:
- try/catch -catch 節に暗黙的with -statement を含む
- V8 は、with -statementがすべてのローカルをシャドウすることを前提としています
これにより、強制x
的にコンテキスト変数になり、コンテキストinner
がキャプチャされるため、死ぬx
まで存在しinner
ます。
一般に、特定の変数が実際に必要以上に長くオブジェクトを保持しないようにしたい場合は、その変数に代入することで、このリンクを簡単に破棄null
できます。