一、作用域作用域链

  • 对象中,有些属性是我们无法访问的,JS引擎内部固有的隐式属性
  • 隐式属性 [[scope]]
  • 它是函数创建时,就生成的一个JS内部隐式属性
  • 它是用于存储函数的作用域链的容器[scope chain],作用域链里存储的就是AO GO
  • AO:函数执行期上下文,函数执行完后,函数体内没有东西被函数以外的东西所占用,那么这个AO就会被销毁;AO是一个即时的存储的容器
  • GO:全局执行期上下文

    1. // AO GO -> 跟作用域作用域链相关所产生的一切问题
    2. // AO:函数执行期上下文,跟函数相关
    3. // 对象
    4. var obj = {
    5. name: 'liangyu',
    6. age: 10,
    7. height: 170,
    8. weight: 55
    9. }
    10. console.log(obj.name);
    11. // 函数也是对象
    12. function test(a, b){
    13. // 打印函数的名字
    14. console.log(test.name);
    15. // 打印函数的形参个数
    16. console.log(test.length);
    17. }
    18. // 对象中,有些属性是我们无法访问的,JS引擎内部固有的隐式属性
    19. // 隐式属性 [[scope]]
    20. // 1. 它是函数创建时,就生成的一个JS内部隐式属性
    21. // 2. 它是用于存储函数的作用域链的容器[scope chain],作用域链里存储的就是AO GO
    22. // AO:函数执行期上下文,函数执行完后,函数体内没有东西被函数以外的东西所占用,那么这个AO就会被销毁;AO是一个即时的存储的容器
    23. // GO:全局执行期上下文
    24. function a(){
    25. function b(){
    26. var b = 3;
    27. }
    28. var a = 1;
    29. b();
    30. }
    31. var c = 3;
    32. a();

    每一个函数的作用域链上都有GO
    image.png
    image.png
    当外层函数执行时,内层函数被定义
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    函数在刚开始被定义的时候,拿的都是上级的环境;只有当函数执行的时候,才会形成自己的AO;自己的AO要排在最顶端

  • 全局执行的前一刻生成 GO;在生成GO的时候,全局的函数已经声明和定义了

  • 全局执行
    1. 找变量声明
    2. 找函数声明并赋值

    1. // GO = {
    2. // test2: function test2(){}
    3. // }
    4. test2();
    5. function test2(){}
    6. // GO = {
    7. // test1: undefined
    8. // }
    9. test1(); // 报错
    10. var test1 = function(){}

    函数在定义的时候就已经生成隐式属性 [[scope]]了,作用域里面最开始存储的是GO,函数在执行前一刻会形成自己的AO,并且排在作用域最顶端

  1. // 函数在定义的时候就已经生成隐式属性 [[scope]]了,作用域里面最开始存储的是GO,函数在执行时会形成自己的AO,并且排在作用域最顶端
  2. function test2(){
  3. function test3(){
  4. }
  5. }
  6. test2();
  7. // GO = {
  8. // test2: function test2(){}
  9. // }
  10. // AO = {
  11. // test3: function test3(){}
  12. // }

二、闭包基础

闭包:内部函数返回到外部并被占用时,就一定会产生闭包;闭包会导致原来的作用域链不被释放;过渡的闭包可能会导致内存泄漏,或者加载过慢

  1. // 闭包基础
  2. // 内部函数返回到外部并保存时,一定会产生闭包;闭包会导致原来的作用域链不被释放
  3. // 过渡的闭包可能会导致内存泄漏,或者加载过慢
  4. function test1(){
  5. function test2(){
  6. var b = 2;
  7. a = 2;
  8. console.log(a);
  9. }
  10. var a = 1;
  11. return test2;
  12. }
  13. var c = 3;
  14. var test3 = test1();
  15. test3();

image.png

image.png

三、闭包的简单应用

3.1、应用一:利用数组返回闭包

利用闭包原理实现累加累减

  1. // 闭包应用一
  2. // 利用闭包原理实现累加累减
  3. function func(){
  4. var n = 100;
  5. function add(){
  6. n++;
  7. console.log(n);
  8. }
  9. function reduce(){
  10. n--;
  11. console.log(n);
  12. }
  13. return [add, reduce];
  14. }
  15. var compute = func();
  16. compute[0]();
  17. compute[0]();
  18. compute[1]();

3.2、应用二:利用数组返回闭包

利用闭包原理实现一个面包管理器

  1. // 利用闭包原理实现一个面包管理器
  2. function breadMgr(num){
  3. var breadNum = arguments[0] || 10;
  4. function supply(){
  5. breadNum += 10;
  6. console.log(breadNum);
  7. }
  8. function sale(){
  9. breadNum--;
  10. console.log(breadNum);
  11. }
  12. return [supply, sale];
  13. }
  14. var breadMgr = breadMgr(50);
  15. breadMgr[0]();
  16. breadMgr[1]();
  17. breadMgr[1]();

3.3、应用三:利用对象返回闭包

利用闭包做一个星期天安排计划

  1. // 利用闭包做一个星期天安排计划
  2. function sunSchedule(){
  3. var sunSchedule = '';
  4. var operation = {
  5. setSchedule: function(thing){
  6. sunSchedule = thing;
  7. console.log(sunSchedule);
  8. },
  9. showSchedule: function(){
  10. console.log('my schedule on sunday is' + ' ' + sunSchedule);
  11. }
  12. }
  13. return operation;
  14. }
  15. var sunSchedule = sunSchedule();
  16. sunSchedule.setSchedule('walking');
  17. sunSchedule.showSchedule();