意味合いとしては「プログラムからは参照されることがない」のだからgcが回収してくれるだろうと期待したくなりますが、他のお二人が回答しておられるように現状の実装ではクロージャー内部で明示的に参照されてなくても参照される可能性がある変数は全て「暗黙に覚えられてしまう」ようですね。
http://www.ecma-international.org/ecma-262/6.0/#sec-lexical-environments
この辺りを読むと「変数などの識別子とその値の対応を保持するEnvironment Record」なるものが解説されてます。「クロージャーの中のコードが実際に参照するかどうか」とは別に宣言されている変数は全てEnvironment Recordから見えてしまう」実装になっているのかどうかはこれだけ見ても自分にははっきりわかりませんでしたが、少なくとも何らかの最適化によりouterが最適化されない限りはEnvironment Recordに不要な変数が存在し続けているような気がします。
しかし、「実際どうなのか」を見た方が単純に納得しやすい(自分自身が)と思ったので実際node 9.0.0でやってみました。
gc.js
javascript
1const process = require('process')
2const linkClosure = process.argv[2] !== void 0
3const linkExplicitly = process.argv[2] === 'explicitly'
4const N = 64
5const GARBAGE_SIZE = 0x10000
6
7function foo() {
8 let a = {next:null, link:null, garbage:null}
9 let garbage = Buffer.alloc(GARBAGE_SIZE)
10
11 totalAllocated += GARBAGE_SIZE
12
13 const f = () => {
14 if (linkClosure) a.link = f;
15 if (linkExplicitly) a.garbage = garbage
16 return a
17 }
18 return f
19}
20
21console.log(`linkClosure = ${linkClosure}, linkExplicitly = ${linkExplicitly}`)
22
23let top
24let totalAllocated = 0
25for (let i = 0; i < 4096; i++) {
26 const f = foo()
27 const a = f()
28 a.next = top
29 top = a
30}
31const mu = process.memoryUsage()
32const report = ['rss', 'heapTotal', 'heapUsed', 'external']
33 .map(k => fmt(mu[k])).join('/')
34console.log(`${fmt(totalAllocated)}: ${report}`)
35
36function fmt(n) {
37 const s = n.toString(16)
38 return " ".repeat(12 - s.length) + s
39}
bash
1$ node gc
2linkClosure = false, linkExplicitly = false
3 10000000: 5605000/ 954000/ 456ec8/ 7fd2020
4$ node gc closure
5linkClosure = true, linkExplicitly = false
6 10000000: 11905000/ a54000/ 554b88/ 10002020
7$ node gc explicitly
8linkClosure = true, linkExplicitly = true
9 10000000: 11908000/ a54000/ 554c60/ 10002020
最初の列は実験対象のオブジェクト(garbage)のトータルの確保量、それ以降の列はprocess.memoryUsageのrss,heapTotal,heapUsed,externalの値です。garbageはBuffer.allocateで確保するようにしてますがこの領域はC++領域(external)に確保されるようです。結果をみるとクロージャーを覚えているだけ(node gc closureの実行)でもgarbageがgcで回収されてないことがわかります。
自分はアマチュアのため「うーん仕様をみてもわからん」という場合、割と安直に実験しようとします。プロの方だと「複数のエンジンに共通な仕様が何か」というもっと上のレベルのことを気にされていると思いますが、javascriptの仕様を把握するのはさぞ大変だろうと常々思います。