闭包

2023-10-20 18:41:03 浏览数 (2)

作用域

想掌握闭包那么就一定要知道什么是作用域。我们先看下面这段代码:

代码语言:javascript复制
function foo() {
  var a = 2;
  console.log(a);
}

foo.a; // undefined

在ES6之前,只有函数可以创建作用域,这里函数foo创建了一个作用域并在该作用域里声明了一个变量a。我们发现,在函数外部是没有办法访问到该变量。作用域的作用之一就是控制变量的访问范围。作用域另外一个作用就是约束了变量的生命周期,也就是说函数执行完毕后作用域内的所有变量都会被销毁

作用域链

上面我们说到作用域控制了变量的访问范围,在作用域外无法访问到作用域里的变量。但是如果是由内而外访问是没有问题的,看下面这段示例代码:

代码语言:javascript复制
function foo() {
  var a = 2;
  function bar() {
    console.log(a);
  }
  bar();
}

foo(); // 2

是的,JavaScript允许函数里声明函数,也就是说,在作用域里创建子作用域,这就是作用域链。而这种嵌套的方式正是闭包

闭包

那作用域和闭包是什么关系呢?闭包英文是“Closure”,中译“关闭”。前面说到内部作用域可以访问上级作用域的变量,外部无法访问内部的作用域。对于外部来说,内部作用域就像是一个封闭的包裹,那有什么办法让外部访问内部呢?

代码语言:javascript复制
function foo() {
  var a = 2;
  function bar() {
    return {
      a
    };
  }
  return bar;
}

var baz = foo()(); // { a: 2 }

我们将函数作为返回值返回,发生了一个奇怪的现象,我们试想,这不就把内部作用域传递到外部了吗?那外部是不是可以由此访问里面嵌套的作用域了吗

闭包是如何产生的

产生闭包的条件:

  • 嵌套函数
  • 内部函数持有外部函数的变量

生命周期

嵌套的内部函数执行完会去销毁闭包

代码语言:javascript复制
function foo() {
  var a = 2;
  bar();
  function bar() {
    console.log(  a);
  }
}

foo(); // 3
foo(); // 3

实际应用

模块化

闭包是模块化开发的基石,代码如下所示:

代码语言:javascript复制
var module1 = (function(){

  var _count = 0;

  var m1 = function(){
    //...
  };

  var m2 = function(){
    //...
  };

  return {
    m1 : m1,
    m2 : m2
  };

})();

防抖

我们在搜索框输入关键词时,如果每输入一个字都去远程加载是非常浪费资源的。防抖可以很好的解决这个问题,在一个延时函数里去实现请求,如果关键词变更了,则清除之前的请求,重新延时加载

代码语言:javascript复制
function debounce(fun, delay) {
    return function (args) {
        let that = this
        let _args = args
        clearTimeout(fun.id)
        fun.id = setTimeout(function () {
            fun.call(that, _args)
        }, delay)
    }
}

function ajax() {}

debounce(ajax, 300);

节流

当我们提交表单的时候,如果误触多次,那么就会导致表单重复提交。节流的做法就是规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

代码语言:javascript复制
 function throttle(fun, delay) {
   let last, deferTimer
   return function (args) {
     let that = this
     let _args = arguments
     let now =  new Date()
     if (last && now < last   delay) {
       clearTimeout(deferTimer)
       deferTimer = setTimeout(function () {
         last = now
         fun.apply(that, _args)
       }, delay)
     }else {
       last = now
       fun.apply(that,_args)
     }
   }
 }

0 人点赞