深入淺出 Scope Chain 與 Closure

栏目: JavaScript · 发布时间: 6年前

内容简介:Closure 是 ECMAScript 的一大特色,但由於對其不了解,因此很多人不敢使用 Closure;或者雖然會使用 Closure,但仍然對其原理一知半解。本文以 Runtime 角度深入探討 Closure 底層機制 Scope Chain,讓我們徹底了解 Closure 的黑魔法。ECMAScript 5

Closure 是 ECMAScript 的一大特色,但由於對其不了解,因此很多人不敢使用 Closure;或者雖然會使用 Closure,但仍然對其原理一知半解。

本文以 Runtime 角度深入探討 Closure 底層機制 Scope Chain,讓我們徹底了解 Closure 的黑魔法。

Version

ECMAScript 5

ECMAScript 2015

Definition

Closure

當 function 的執行 scope 已經離開 function 所定義的 scope 時,該 function 依然能夠抓到原 scope 的 variable 繼續執行

ECMAScript 5

const makeCounter = function(initial) {
  return function(step) {
    return initial += step;
  }
};

const counter = makeCounter(2);

console.log(counter(1)); // 3
console.log(counter(2)); // 5
console.log(counter(3)); // 8

ECMAScript 2015

const makeCounter = initial =>
  step => initial += step;

const counter = makeCounter(2);

console.log(counter(1)); // 3
console.log(counter(2)); // 5
console.log(counter(3)); // 8

這是最簡單的 Closure,ES5 與 ES6 的寫法有一點點差異。

initial 是定義在 makeCounter() scope 內,然後 return Anonymous function 給 counter

counter() 執行時,還能抓到 initial parameter,這就是 Closure

Stack 疑雲

我們知道 function 與 method 的 parameter 與 local variable,在執行時期都是存放在 Stack。

執行 makeCounter() 時, initial parameter 是存放在 Stack,當 makeCounter() 回傳 function 給 counter 後,Stack 會釋放,因此 initial parameter 也會被釋放,為什麼再次執行 counter() 時,還會抓到 initial parameter 呢 ?

Scope Chain

在 ECMAScript 中,所有的 variable 都是定義在 scope object 內,由 key / value 構成,也因為是 object, scope 是在 Heap 內。

const makeCounter = function(initial) {
  return function(step) {
    return initial += step;
  }
};

深入淺出 Scope Chain 與 Closure

在 code 執行前,ECMAScript 會將所有 variable 存在 global scope object 內。

因此我們有 key 為 makeCounter ,而 value 指向 function 的定義 object。

比較特別的是:每個 function object 有 hidden property [[scope]] 指向定義該 function 的 scope object。

makeCounter(2);

深入淺出 Scope Chain 與 Closure

當執行 makeCounter(2) 時,會有自己新的 function scope,因此會建立新的 scope object。

新的 scope object 一樣是由 key / value 構成,除了有 function 該有的 thisarguments 外,還有 initial parameter。

雖然我們是直接 return anonymous function,仍然可以想成有一個 key 為 f ,而 value 指向 function 的定義 object,他也有 [[scope]] 指向 makeCounter() 的 scope object。

比較特別的是:新的 function scope object 有一個 property : outer 指向定義 makeCounter() 的 global scope object,這個 reference 正是由 [[scope]] 複製而來。

const counter = makeCounter(2);

深入淺出 Scope Chain 與 Closure

在 global scope object 的 key 新增 counter ,其 value 指向所 return 的 anonymous function。

counter(1);

深入淺出 Scope Chain 與 Closure

當執行 counter(1) 時,又有新的 scope object 建立,一樣有 thisarguments ,也有 step parameter 為 1

outer property 亦由 [[scope]] 複製而來,因此可以指向 makeCounter() 的 scope object。

當要執行 initial += step 時,在 counter() 的 scope object 並沒有 key 為 initial 的 property,怎麼辦呢 ?

此時 ECMAScript 會透過 outer property 往上找,在 makeCounter() scope object 找到 initial

由於 scope object 會透過 outer[[scope]] 一層一層往上找,因此稱為 Scope Chain ,這是 Closure 之所以能正常執行的原因。

Conclusion

  • Scope object 因為是放在 Heap,而不是放在 Stack,因此不會隨著 function 執行完而釋放
  • 只要 scope object 被其他 scope object 的 outer property 所參考,則 ECMAScript runtime 的 Garbage Collection 就不會釋放該 scope object,因此 Closure 可以正常執行

以上所述就是小编给大家介绍的《深入淺出 Scope Chain 與 Closure》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品型社群

产品型社群

李善友 / 机械工业出版社 / 2015-3-1 / CNY 69.00

传统模式企业正在直面一场空前的“降维战争”, 结局惨烈,或生或死。 传统模式很难避免悲惨下场, 诺基亚等昔日庞然大物轰然倒塌, 柯达发明了数码成像技术却依然破产, 新商业的兴起到底遵循的是什么模式? 微信轻而易举干掉了运营商的短信业务, “好未来”为何让传统教育不明觉厉? 花间堂为什么不是酒店,而是入口? 将来不会有互联网企业与传统企业之分, ......一起来看看 《产品型社群》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器