zoukankan      html  css  js  c++  java
  • 闭包函数

    • 作用域链
      • 由于作用域是相对于变量而言的,而如果存在多级作用域,这个变量又来自于哪里?这个问题就需要好好地探究一下了,我们把这个变量的查找过程称之为变量的作用域链
      • 作用域链的意义:查找变量(确定变量来自于哪里,变量是否可以访问)
      • 简单来说,作用域链可以用以下几句话来概括:(或者说:确定一个变量来自于哪个作用域)
        • 查看当前作用域,如果当前作用域声明了这个变量,就确定结果
        • 查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明
        • 再查找上级函数的上级函数,直到全局作用域为止
        • 如果全局作用域中也没有,我们就认为这个变量未声明(xxx is not defined)
        var name = 'sunny';
        (()=>{
            var name = 'storm';
            console.log(name);
        })();
    
        var name = 'sunny';
        (()=>{
            console.log(name);
            var name = 'storm';
        })();
    
        var name = "sunny";
        var f1 = ()=> {
            return ()=>{
                console.log(name);
            }
            var name="storm";
        }
        var nameNew = f1();
        nameNew();
    
        var name = "sunny";
        var f1 = ()=>{
            return {
                say:()=>{
                    console.log(name);
                    var name = "storm";
                }
            }
        }
        var nameNew = f1();
        console.log(nameNew.say());
    
    • 闭包函数的实现
      • 函数执行完毕后,作用域中保留了最新的timer变量的值
      • 闭包函数常应用于模块化开发,防止变量被破坏
        var count = ()=>{
            var timer = 0;
            var c = ()=>{
                return timer++;
            }
            return c;
        }
        var counter = count();
        console.log(counter());
        console.log(counter());
        console.log(counter());
    
    • 闭包的创建

      • 先用外层函数封装一个受保护的局部变量
      • 再在内层函数中操作外层函数的变量
      • 外层函数将内层函数返回到外部,在外部反复调用
    • 闭包的判断

      • 函数嵌套!
      • 内层函数使用外层函数的局部变量
      • 内层函数被返回到外部,在外部调用
    • 判断闭包输出

      • 同一次外层函数调用返回的内层函数,操作同一个变量
      • 外层函数调用了几次,就有几个受保护的变量副本
    • 闭包的优缺点

      • 优点:即要重用变量,又要保护变量不被污染
      • 缺点:占用更多内存空间——因为outer的活动对象无法释放
    • 函数的四种调用方式

      • 在ES6的箭头函数之前的时代,想要判断一个函数内部的this指向谁,就是根据这四种方式来决定的,函数内部的this跟大小写、书写位置无关
      • 函数调用
      • 方法调用
      • 构造函数调用(new)
      • 上下文方式调用(call、apply、bind)
        // 函数调用,this指向window
        var age = 18;
        var person = {
            age:15,
            say:function(){
                console.log('我今年' + this.age + '岁!');
            }
        }
        var sunny = person.say;
        sunny(); 
    
        // 方法调用,this指向对象person
        var age = 18;
        var person={
            age:15,
            say:function (){
                console.log('我今年' + this.age + '岁!');
            }
        }
        person.say();
    
        // 构造函数调用,this将指向构造函数实例本身
        var age=18;
        var person={
            age:15,
            say:function(){
                console.log('我今年' + this.age + '岁!');
            }
        }
        new person.say();
    
        //上下文调用方式,有3种,call、apply、bind
        function f1(){
            console.log(this);
        }
        //call方法的第一个参数决定了函数内部的this的值
        f1.call([1,3,5])
        f1.call({age:20,height:1000})
        f1.call(1)      
        f1.call("abc")
        f1.call(true);
        f1.call(null)
        f1.call(undefined);
    
        //上述代码可以用apply完全替换
    
        //总结:
        //call方法的第一个参数:
        //1、如果是一个对象类型,那么函数内部的this指向该对象
        //2、如果是undefined、null,那么函数内部的this指向window
        //3、如果是数字-->this:对应的Number构造函数的实例
        //      -->   1   --> new Number(1)
        //  如果是字符串-->this:String构造函数的实例
        //      --> "abc"   --> new String("abc")
        //  如果是布尔值-->this:Boolean构造函数的实例
        //      --> false   --> new Boolean(false)
    
    • bind()函数
        // 普通方法调用
        var person = {
            age:18,
            run : function(){
                console.log(this);  //this指向person
                var _that=this;
                setTimeout(function(){
                    console.log(this.age); //this指向window
                    console.log(_that.age); 
                },50);
            }
        }
        person.run();
    
    // 通过执行了bind方法,匿名函数本身并没有执行,只是改变了该函数内部的this的值,指向person
    var person = {
        age:18,
        run : function(){
            console.log(this);  // this指向person
            setTimeout((function(){
                console.log(this.age); 
            }).bind(this),50);  // 绑定this指向person
        }
    }
    person.run();
    
        // bind函数基本用法
        function speed(){
            console.log(this.seconds);
        }
        speed({ seconds:100 });
        // 执行了bind方法之后,产生了一个新函数,
        // 这个新函数里面的逻辑和原来还是一样的,唯一的不同是this指向{ seconds:100 }
        var speedBind = speed.bind({ seconds:100 });
        speedBind();    //100
    
        // bind函数常规写法
        (function eat(){
            console.log(this.seconds);
        }).bind({ seconds:360 })()  
    
        // bind函数案例
        var obj={
            name:"西瓜",
            drink:(function(){
                //this指向了:{ name:"橙汁" }
                console.log(this.name);
            }).bind({ name:"橙汁" })
        }
        obj.drink();    //"橙汁"
    
        var p10={
            height:88,
            run:function(){
                //this
                setInterval((function(){
                    console.log(this.height);   //88
                }).bind(this),100)  
            }
        }
        p10.run();
    
        // 手写bind函数
        Function.prototype._bind = target => {
            // 这里的this指向函数实例
            // target表示新函数的内部的this的值
            // 利用闭包创建一个内部函数,返回那个所谓的新函数
            return () => {
                this.call(target);
            }
        }
        function person(){
            console.log(this);
        }
        person();
        var sunny = person.bind({age:18});
        sunny();
    
  • 相关阅读:
    在Eclipse上实现简单的JDBC增删查改操作
    Java学习路线:day12 面向对象(中)
    Java学习路线:day11 客户信息管理软件
    Android个人手机通讯录开发详解
    解决:keeps stopping(停止运行)
    Java学习路线:day10 面向对象(上)3
    2020最新版大数据学习路线
    Java学习路线:day9 面向对象(上)2
    一个简单的ASP登录页面
    Python笔记_第四篇_高阶编程_检测_2.对类进行单元检测
  • 原文地址:https://www.cnblogs.com/SharkJiao/p/13548207.html
Copyright © 2011-2022 走看看