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();
    
  • 相关阅读:
    POJ 1300 Open Door
    POJ 2230 Watchcow
    codevs 1028 花店橱窗布置
    codevs 1021 玛丽卡
    codevs 1519 过路费
    codevs 3287 货车运输
    codevs 3305 水果姐逛水果街二
    codevs 1036 商务旅行
    codevs 4605 LCA
    POJ 1330 Nearest Common Ancestors
  • 原文地址:https://www.cnblogs.com/SharkJiao/p/13548207.html
Copyright © 2011-2022 走看看