闭包介绍

作者: 凛冬已至_123 | 来源:发表于2018-05-15 16:57 被阅读0次

    闭包


    关于闭包的定义:

    A closure is the combination of a function and the lexical environment within which that function was declared. --MDN
    A closure is the local variables for a function - kept alive after the function has returned . --javascriptkit

    词法作用域 (lexical environment)

    作用域链:

    • 函数在执行的过程中,先从自己内部找变量
    • 如果找不到,再从创建当前函数所在的作用域(词法作用域)去找, 以此往上
    • 注意找的是变量的当前的状态
      函数连同它作用域链上的要找的这个变量,共同构成闭包
      一般情况下使用闭包主要是为了
    1. 封装数据
    2. 暂存数据
      一个典型的闭包案例
    function car(){
      var speed = 0
      function fn(){
        speed++
        console.log(speed)
      }
      return fn
    }
    
    var speedUp = car()
    speedUp()   //1
    speedUp()   //2
    

    闭包相关案例


    理解了下面几个案例,你就能熟练理解运用闭包了
    如下代码输出多少?如果想输出3,那如何改造代码?

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
      fnArr[i] =  function(){
        return i
      };
    }
    console.log( fnArr[3]() ) // 10
    

    改造后

    var fnArr = []
    for (var i = 0; i < 10; i ++) {
      fnArr[i] =  (function(j){
        return function(){
          return j
        } 
      })(i)
    }
    console.log( fnArr[3]() ) // 3
    var fnArr = []
    for (var i = 0; i < 10; i ++) {
      (function(i){
        fnArr[i] =  function(){
          return i
        } 
      })(i)
    }
    console.log( fnArr[3]() ) // 3
    var fnArr = []
    for (let i = 0; i < 10; i ++) {
      fnArr[i] =  function(){
        return i
      } 
    }
    console.log( fnArr[3]() ) // 3
    

    封装一个 Car 对象

    var Car = (function(){
       var speed = 0;
       function set(s){
           speed = s
       }
       function get(){
          return speed
       }
       function speedUp(){
          speed++
       }
       function speedDown(){
          speed--
       }
       return {
          setSpeed: setSpeed,
          get: get,
          speedUp: speedUp,
          speedDown: speedDown
       }
    })()
    Car.set(30)
    Car.get() //30
    Car.speedUp()
    Car.get() //31
    Car.speedDown()
    Car.get()  //30
    

    如下代码输出多少?如何连续输出 0,1,2,3,4

    for(var i=0; i<5; i++){
      setTimeout(function(){
        console.log('delayer:' + i )
      }, 0)
    }
    

    修改后

    for(var i=0; i<5; i++){
      (function(j){
        setTimeout(function(){
          console.log('delayer:' + j )
        }, 0)    
      })(i)
    }
    

    或者

    for(var i=0; i<5; i++){
      setTimeout((function(j){
        return function(){
          console.log('delayer:' + j )
        }
      }(i)), 0)    
    }
    

    如下代码输出多少?

    function makeCounter() {
      var count = 0
    
      return function() {
        return count++
      };
    }
    
    var counter = makeCounter()
    var counter2 = makeCounter();
    
    console.log( counter() ) // 0
    console.log( counter() ) // 1
    
    console.log( counter2() ) // ?
    console.log( counter2() ) // ?
    //还是0/1,counter2是一个新创建的函数
    

    补全代码,实现数组按姓名、年纪、任意字段排序

    var users = [
      { name: "John", age: 20, company: "Baidu" },
      { name: "Pete", age: 18, company: "Alibaba" },
      { name: "Ann", age: 19, company: "Tecent" }
    ]
    
    users.sort(byName) 
    users.sort(byAge)
    users.sort(byField('company'))
    

    答:

    function byName(user1, user2){
      return user1.name > user2.name
    }
    
    function byAge (user1, user2){
      return user1.age > user2.age
    }
    
    function byFeild(field){
      return function(user1, user2){
        return user1[field] > user2[field]
      }
    }
    users.sort(byField('company'))
    

    写一个 sum 函数,实现如下调用方式

    console.log( sum(1)(2) ) // 3
    console.log( sum(5)(-1) ) // 4
    

    答:

    function sum(a) {
      return function(b) {
        return a + b
      }
    }
    

    函数柯里化-只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。

    相关文章

      网友评论

        本文标题:闭包介绍

        本文链接:https://www.haomeiwen.com/subject/ohkydftx.html