JS的做用域、闭包

前言

做为一名前端闭包知识点在面试汇总常常问道,工做中也会常常用到,下面讲下我本身对闭包的认识,但愿对各位有所帮助;在讲解闭包以前会先讲解一些和闭包有关的一些知识和概念,方便更好的理解闭包;前端

闭包前置知识

什么是做用域

做用域是使用一套严格的规则来分辨哪些标识符对那些语法有访问权限。通俗的讲,做用域就是查找变量的地方,做用域能够分为动态做用域个静态做用域;面试

请看例子:缓存

var a=1
function myFun(){
    var b=2
    console.log(a) //1
    console.log(b) //2
}
myFun() 
复制代码

上面代码定义了一个变量和一个函数,函数执行的时候输出变量a的值1和变量b的值2,此时有一个全局做用域,在全局做用域内部声明了变量和函数myFun,而在函数内部就造成一个函数做用域,在这个做用域内有变量b值为2;bash

做用域链

结合上面的例子咱们在函数内部查找a变量的时候,先在函数做用域中查找,没有找到,就去上一级的做用域去找,直到找到全局做用域,也就是在查找标识符的过程汇总有一个往外层查找的过程。好像是顺着一条链条从下往上查找,这条链条,咱们就称之为做用域链。闭包

做用域嵌套

在尚未接触到ES6的let、const以前,只有函数做用域和全局做用域,函数做用域确定是在全局做用域里面的,而函数做用域中又能够继续嵌套函数做用域,如图:函数

上图代表了做用域的嵌套关系,而在查找标识符的时候,也是从内向外查找的,这从里到外的各层做用域就组成了做用域链。

JS中的做用域类型

全局做用域

最外层的做用域性能

函数做用域

函数做用域是js中最多见的做用域了,函数做用域给咱们最直观的体会就是,内部函数能够调用外部函数中的变量。一层层的函数,很直观的就造成了嵌套的做用域。ui

块级做用域

ES6 提供的let,const方法声明的标识符都会固定于块中。常被你们忽略的try/catch的catch语句也会建立一个块做用域。spa

词法做用域

概念

“词法做用域是做用域的一种工做模型”, 所谓的词法做用域就是在你写代码时将变量和块做用域写在哪里来决定,也就是词法做用域是静态的做用域,编译阶段就可以知道所有标识符在哪里以及是如何声明的。设计

闭包

什么是闭包

《JavaScript高级程序设计》这样描述:

闭包是指有权访问另外一个函数做用域中的变量的函数; 《你不知道的JavaScript》这样描述: 当函数能够记住并访问所在的词法做用域时,就产生了闭包,即便函数是在当前词法做用域以外执行。

闭包使用场景

  • 设计私有的方法和变量(封装,定义模块)。
var counter = (function(){
        var privateCounter = 0; //私有变量
        function change(val){
            privateCounter += val;
        }
        return {
            increment:function(){  
                change(1);
            },
            decrement:function(){
                change(-1);
            },
            value:function(){
                return privateCounter;
            }
        };
    })();
复制代码
  • 设置缓存
var fn=(function(){
    var cache={}//将结果缓存到该对象中
    return function(){
        var str=JSON.stringify(arguments);
        if(cache[str]){//判断缓存中是否存在传递过来的参数,存在直接返回结果,无需计算
            return cache[str];
        }else{//进行计算并返回结果
            var sum=0;
            for(var i=0;i<arguments.length;i++){
                sum+=arguments[i];
            }
            return cache[str]=sum;
        }
    }
})()
复制代码

上面的示例将计算后的结果缓存到局部变量cache当中,在调用这个函数时,先在缓存中查找,若是找不到,则进行计算,而后将结果放到缓存中并返回,若是找到了,直接返回查找到的值。

  • 在函数外使用函数内的变量
function init(){
    var a = "1";//a是一个被init建立的局部变量
    function sayA(){//sayA是一个内部函数,闭包
        alert(a);//a
    }
    sayA();
}
init();//"a"
复制代码

闭包性能

  • 闭包的缺点就是常驻内存会增大内存使用量,而且使用不当很容易形成内存泄露。

  • 若是不是由于某些特殊任务而须要闭包,在没有必要的状况下,在其它函数中建立函数是不明智的,由于闭包对脚本性能具备负面影响,包括处理速度和内存消耗。

  • 能够读取函数内部的变量。

  • 可让这些局部变量保存在内存中,实现变量数据共享。

相关文章
相关标签/搜索