AOGO主要是用来解决「作用域」和「作用域链」相关所产生的一切问题。
AOfunction相关,函数相当于一个独立的仓库,比如A仓库和B仓库。

作用域 & 作用域链

我们都知道在JavaScript中「一切皆对象」,每个对象都有自己的属性和方法。

  1. var obj = {
  2. name: "1",
  3. address: "1",
  4. teach: function () {},
  5. };
  6. console.log(obj.name);

而函数也是一种对象类型(引用类型)。

  1. function test(param1,param2) {}
  2. console.log(test.name); // 函数的名字
  3. console.log(test.length); // 形参的个数

JavaScript中对象有一些属性是我们无法访问的,它们是JS引擎固有的「隐式属性」,是不供外界访问的(私有属性)。

那什么是作用域[[scope]]呢???

  1. 函数创建时生成的一个JS内部的隐式属性
  2. 函数存储作用域链的容器,作用域链存储的是AOGo对象,每个函数的作用域链都是独立的!!!
    1. AO是函数执行期上下文对象
    2. GO是全局执行期上下文对象
  3. AO是一个即时存储的容器,当函数执行完成之后,AO是要被销毁的,再次执行函数,AO会重新生成。

下面来看一个例子:

  1. function a() {
  2. function b() {
  3. var b = 2;
  4. }
  5. var a = 1;
  6. b();
  7. }
  8. var c = 3;
  9. a();

以上以一段完整的代码,我们将代码逐步分解:
作用域、作用域链、闭包基础 - 图1

以上图解作用域链的时候,我们可以总结出:
函数被定义的时候就已经生成了[[scope]][[scope]]已经存储了Scope Chain(作用域链),作用域链已经存储了GO
而函数执行的前一刻才生成的函数自己的AO

为什么函数的外部无法访问函数内部的变量呢?
从图中我们可以得知,作用域链是自上而下执行的,所以b函数可以访问a函数的变量,反过来则不行。

  1. function a() {
  2. function b() {
  3. var b = 2;
  4. console.log(a); // 1
  5. }
  6. var a = 1;
  7. b();
  8. console.log(b); // error
  9. }
  10. var c = 3;
  11. a();

下面再来举个例子🌰 :

  1. function a() {
  2. function b() {
  3. function c() {}
  4. c();
  5. }
  6. b();
  7. }
  8. a();
  9. // 以上代码的作用域链是:
  10. /**
  11. * a定义:
  12. * a.[[scope]] > [GO]
  13. * a执行
  14. * a.[[scope]] > [AO,GO]
  15. * b定义
  16. * b.[[scope]] > [AO,GO]
  17. * b执行
  18. * b.[[scope]] > [AO,AO,GO]
  19. * c定义
  20. * c.[[scope]] > [AO,AO,GO]
  21. * c执行
  22. * c.[[scope]] > [AO,AO,AO,GO]
  23. */
  24. /**
  25. * c结束:
  26. * c.[[scope]] > [AO,AO,GO]
  27. * b结束:
  28. * b.[[scope]] > [AO,GO],c.[[scope]] 销毁
  29. * a结束:
  30. * a.[[scope]] > [GO],b.[[scope]] 销毁
  31. */

闭包

当内部函数被返回到外部并保存的时候,就一定会产生闭包

  • 闭包会产生原来的作用域链不释放
  • 过度的闭包可能会导致内存泄漏或加载过慢

举栗 🌰 :

  1. function test1() {
  2. function test2() {
  3. var b = 2;
  4. console.log(a);
  5. }
  6. var a = 1;
  7. return test2;
  8. }
  9. var c = 3;
  10. var test3 = test1();
  11. test3();

作用域、作用域链、闭包基础 - 图2

以上图解解释了什么是闭包。

举栗子🌰 :

  1. function test() {
  2. var n = 100;
  3. function add() {
  4. n++;
  5. }
  6. function reduce() {
  7. n--;
  8. console.log(n);
  9. }
  10. return [add, reduce];
  11. }
  12. var arr = test();
  13. arr[0](); // 101
  14. arr[1](); // 100

因为addreduce被保存到了外部执行,test函数的AO并没有被销毁,所以addreduce操作的其实都是test函数的n

同理看下面的例子:

  1. function breadMgr(num) {
  2. var breadNum = num || 10;
  3. function supply() {
  4. breadNum += 10;
  5. console.log(breadNum);
  6. }
  7. function sale() {
  8. breadNum--;
  9. console.log(breadNum);
  10. }
  11. return [supply, sale];
  12. }
  13. var breadMgr = breadMgr();
  14. breadMgr[0](); // 20
  15. breadMgr[1](); // 19
  1. function sunSched() {
  2. var sunSched = "";
  3. var operation = {
  4. setSched: function (thing) {
  5. sunSched = thing;
  6. },
  7. showSched: function () {
  8. console.log("My schedule on sunday is " + sunSched);
  9. },
  10. };
  11. return operation;
  12. }
  13. var sunSched = sunSched();
  14. sunSched.setSched("studying");
  15. sunSched.showSched(); // My schedule on sunday is studying