乐趣区

关于前端:面试闭包

1. 什么是闭包

须要说到作用域、作用域链、变量晋升、暂时性死区、执行上下文等

作用域:

  • 一套变量放在哪,如何拜访、批改的规定
  • 在 js 编译阶段,遍历作用域查以后的变量是否存在,如果存在就疏忽该变量,持续下一个。如果不存在就在当初的作用域创立一个
  • 在执行阶段,会在以后作用域查找该变量,如果找不到会向父作用域查找,直到最外层
  • JS 中共有 3 种作用域:

    • 全局作用域:定义在全局的变量领有该作用域
    • 函数作用域:定义在函数内的变量领有该作用域
    • 块级作用域:let、const 定义在 {} 中的变量领有该作用域

作用域链:

  • 作用域之间存在嵌套关系,就造成了作用域链

闭包:

  • 在一个函数内存在,既不是函数参数,又不是函数的局部变量的变量,这个函数就是闭包

词法作用域和动静作用域

  • 词法作用域:作用域链沿着定义的地位延长,js 之这种
  • 动静作用域:作用域链沿着调用栈延长
  • js 中如何批改

    • eval:把一段 string 转为 js 代码执行
    • width:会独自创立一个作用域
    • 决定不要用他们写代码

2. 看代码说后果

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

结过:4 个 5
起因:setTimout 提早执行,定义的函数中没有 i,就会向外层作用域找,此时 i 曾经是 5 了
如何革新:- 利用 setTimout 的第三个参数
for (var i = 0; i < 5; i++) {setTimeout(function(j) {console.log(j);
    }, 1000, i);
}
- 利用函数缓存变量
for (var i = 0; i < 5; i++) {(function(j) {setTimeout(function() {console.log(i);
          }, 1000);
      })(i)
    
}
var a = 1;
function test(){
    a = 2;
    return function(){console.log(a);
    }
    var a = 3;
}
test()();

后果:2
起因:var a = 3 的定义被变量晋升了,test 外部的函数会用它作用域内的 a 变量,所以是 2. 要留神是 function 定义的地位找,不是应用的中央往外层找

3. 开发中的利用

  • 实现公有变量:局部比拟私密的变量,只想在对象外部失效,不能在内部拜访
  • 实现偏函数、柯里化:能够实现将多个入参函数转为更少入参函数的办法

    function generateName(prefix, type, itemName) {return prefix + type + itemName}
    
    在应用时,第一个、第二个参数可能常常是固定的变量,这时就能够柯里化。function generateName(prefix) {return function(type) {return function (itemName) {return prefix + type + itemName}    
    }
    }
    
    // 生成专属函数
    var countryName = generateName('中国')
    // 应用专属函数
    var cityName = countryName('广东')('广州')
     柯里化把所有的参数都分拆为一个,偏函数更加随便,能够差分为不同的个,例如:function generateName(prefix) {return function(type, itemName) {return prefix + type + itemName}
    }
    
    // 生成专属函数
    var countryName = generateName('中国')
    // 应用专属函数
    var cityName = countryName('广东','广州')
    
退出移动版