AO和GO主要是用来解决「作用域」和「作用域链」相关所产生的一切问题。AO和function相关,函数相当于一个独立的仓库,比如A仓库和B仓库。
作用域 & 作用域链
我们都知道在JavaScript中「一切皆对象」,每个对象都有自己的属性和方法。
var obj = {name: "1",address: "1",teach: function () {},};console.log(obj.name);
而函数也是一种对象类型(引用类型)。
function test(param1,param2) {}console.log(test.name); // 函数的名字console.log(test.length); // 形参的个数
在JavaScript中对象有一些属性是我们无法访问的,它们是JS引擎固有的「隐式属性」,是不供外界访问的(私有属性)。
那什么是作用域[[scope]]呢???
- 函数创建时生成的一个
JS内部的隐式属性 - 函数存储作用域链的容器,作用域链存储的是
AO和Go对象,每个函数的作用域链都是独立的!!!AO是函数执行期上下文对象GO是全局执行期上下文对象
 AO是一个即时存储的容器,当函数执行完成之后,AO是要被销毁的,再次执行函数,AO会重新生成。
下面来看一个例子:
function a() {function b() {var b = 2;}var a = 1;b();}var c = 3;a();
以上以一段完整的代码,我们将代码逐步分解:
以上图解作用域链的时候,我们可以总结出:
函数被定义的时候就已经生成了[[scope]],[[scope]]已经存储了Scope Chain(作用域链),作用域链已经存储了GO。
而函数执行的前一刻才生成的函数自己的AO
为什么函数的外部无法访问函数内部的变量呢?
从图中我们可以得知,作用域链是自上而下执行的,所以b函数可以访问a函数的变量,反过来则不行。
function a() {function b() {var b = 2;console.log(a); // 1}var a = 1;b();console.log(b); // error}var c = 3;a();
下面再来举个例子🌰 :
function a() {function b() {function c() {}c();}b();}a();// 以上代码的作用域链是:/*** a定义:* a.[[scope]] > [GO]* a执行* a.[[scope]] > [AO,GO]* b定义* b.[[scope]] > [AO,GO]* b执行* b.[[scope]] > [AO,AO,GO]* c定义* c.[[scope]] > [AO,AO,GO]* c执行* c.[[scope]] > [AO,AO,AO,GO]*//*** c结束:* c.[[scope]] > [AO,AO,GO]* b结束:* b.[[scope]] > [AO,GO],c.[[scope]] 销毁* a结束:* a.[[scope]] > [GO],b.[[scope]] 销毁*/
闭包
当内部函数被返回到外部并保存的时候,就一定会产生闭包
- 闭包会产生原来的作用域链不释放
 - 过度的闭包可能会导致内存泄漏或加载过慢
 
举栗 🌰 :
function test1() {function test2() {var b = 2;console.log(a);}var a = 1;return test2;}var c = 3;var test3 = test1();test3();

以上图解解释了什么是闭包。
举栗子🌰 :
function test() {var n = 100;function add() {n++;}function reduce() {n--;console.log(n);}return [add, reduce];}var arr = test();arr[0](); // 101arr[1](); // 100
因为add和reduce被保存到了外部执行,test函数的AO并没有被销毁,所以add和reduce操作的其实都是test函数的n。
同理看下面的例子:
function breadMgr(num) {var breadNum = num || 10;function supply() {breadNum += 10;console.log(breadNum);}function sale() {breadNum--;console.log(breadNum);}return [supply, sale];}var breadMgr = breadMgr();breadMgr[0](); // 20breadMgr[1](); // 19
function sunSched() {var sunSched = "";var operation = {setSched: function (thing) {sunSched = thing;},showSched: function () {console.log("My schedule on sunday is " + sunSched);},};return operation;}var sunSched = sunSched();sunSched.setSched("studying");sunSched.showSched(); // My schedule on sunday is studying
