闭包深入浅出

闭包

变量作用域

  • 变量作用域的概念:就是一个变量可以使用的范围
  • JS中首先有一个最外层的作用域:称之为全局作用域
  • JS中还可以通过函数创建出一个独立的作用域,其中函数可以嵌套,所以作用域也可以嵌套
var age=18;     //age是在全局作用域中声明的变量:全局变量

function f1(){
    console.log(name);      //可以访问到name变量
    var name="周董" //name是f1函数内部声明的变量,所以name变量的作用域就是在f1函数内部

    console.log(name);      //可以访问到name变量

    console.log(age);       //age是全局作用域中声明的,所以age也可以访问
}

console.log(age);       //也可以访问
    //多级作用域
    //-->1级作用域
    var gender="男";
    function fn(){
        //问题:
        //gender:可以访问
        //age:  可以访问
        //height:不能访问
        var age=5;

        //-->2级作用域
        return function(){
            //问题:
            //gender:   通过一级一级作用域的查找,发现gender是全局作用域中声明的变量
            //age:
            //height:
            console.log(gender);

            //-->3级作用域
            var height=180;
        }
    }

作用域链

  • 由于作用域是相对于变量而言的,而如果存在多级作用域,这个变量又来自于哪里?这个问题就需要好好地探究一下了,我们把这个变量的查找过程称之为变量的作用域链

  • 作用域链的意义:查找变量(确定变量来自于哪里,变量是否可以访问)

  • 简单来说,作用域链可以用以下几句话来概括:(或者说:确定一个变量来自于哪个作用域)

    • 查看当前作用域,如果当前作用域声明了这个变量,就确定结果
      • 查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明
        • 再查找上级函数的上级函数,直到全局作用域为止
          • 如果全局作用域中也没有,我们就认为这个变量未声明(xxx is not defined)
  • 举例1:

    var name="张三";
    function f1(){
        var name="abc";
        console.log(name);
    }
    f1();
  • 举例2:
    var name="张三";
    function f1(){
        console.log(name);
        var name="abc";
    }
    f1();
  • 举例3:
    var name="张三";
    function f1(){
        console.log(name);
        var name="abc";
    }
    f1();
  • 举例4:
    var name="张三";
    function f1(){
        return function(){
            console.log(name);
        }
        var name="abc";
    }
    var fn=f1();
    fn();
  • 举例5:
    var name="张三";
    function f1(){
        return {
            say:function(){
                console.log(name);
                var name="abc";
            }
        }
    }
    var fn=f1();

闭包的问题

    function fn(){
        var a=5;
        return function(){
            a++;
            console.log(a);
        }
    }
    var f1=fn();
    f1();  //6
    f1(); //7
    f1();//8

闭包问题的产生原因

  • 函数执行完毕后,作用域中保留了最新的a变量的值

闭包的应用场景

  • 模块化
  • 防止变量被破坏

函数的4种调用方式

  • ES6之前,函数内部的this是由该函数的调用方式决定的
    • 函数内部的this跟大小写、书写位置无关
  • 1、函数调用(谁调用指向谁)
    var age=18;
    var p={
        age:15
        say:function(){
            console.log(this.age);//window.age:18
        }
    }
    var s1=p.say
    s1();       //函数调用
  • 2、方法调用
    var age=18;
    var p={
        age:15
        say:function(){
            console.log(this.age);//this:p
            //this.age->p.age:15
        }
    }
    p.say()//方法调用
  • 3、new调用(构造函数)
    var age=18;
    var p={
        age:15
        say:function(){
            //this:say构造函数的实例,实例中并没有age属性,值为:undefined
            console.log(this.age);
        }
    }
    new p.say()//构造函数调用
    //相当于:
    var s1=p.say;
    new s1();
  • 4、上下文方式(call、apply、bind)
    var length=21;
    function f1(){
        console.log(this.length);
    }
    f1.call([1,3,5])    //3
    f1.apply(this)      //window.length:21
    f1.call(5)          //undefined
  • 上下文模式应用场景:
    • 一些需要指定this的情况,比如$.each方法回调函数内部的this
    • 判断数据类型:
      • Object.prototype.toString.call(1);
  • 在ES6的箭头函数之前的时代,想要判断一个函数内部的this指向谁,就是根据上面的四种方式来决定的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值