美文网首页
面向对象之闭包及设计模式的简单介绍day06

面向对象之闭包及设计模式的简单介绍day06

作者: Ainy尘世繁花终凋落 | 来源:发表于2017-03-18 20:40 被阅读0次

    闭包及设计模式的简单介绍

    1.作用域变量搜索规则

    在函数内部声明变量不会覆盖上一层作用域中同名的变量

    总结作用域的画法:

    • (1) 先画出0及级作用域链

      001 先找出有哪些全局的变量 a f1 f2 b
      002 连线(箭头 同级别的变量互相访问)

    • (2) 画出1级作用域链

      001 找函数 f1 延伸出一条线

      002 再在这条线上面画出当前函数内部的所有变量

    • (3) 重复第二个步骤

    作用域:

    1. 全局作用域
    2. 函数作用域
    • 在代码中函数可以创建作用域
    • 函数内部又可以声明函数,创建了新的作用域
    • 函数内部的函数内部又可以声明函数

    作用域的访问规则:

    • 01 先在自己的作用域中查找,如果找不到那么就去上一级查找
    • 02 在外部作用域中不能访问函数内部作用域

    对象:实例属性|方法 原型属性|方法
    obj.name

    eg:

    <script>
    var a = 'testA';
    function f1(){
    
        function f3(){
            var c = 'testC';
        }
    }
    
    function f2(){
    
    }
    var b = 'testB';
    </script>
    <script>
    var a = 'testA';
    function test1(){
        var a ;
        console.log(a);//undefined
        a = 20;
        console.log(a);//20
    }
    console.log(a);//testA
    test1();//undefined  20
    console.log(a);//testA
    </script>
    

    图形解析:


    作用域链的图解

    eg:图为上图:

    <script>
        var a = "testA";
        function f1() {
            var b = "testB";
            function f2() {
                var i ;
                var k ;
            }
        }
        function f3() {
            var c = "testC";
            function f4() {
                var d = "testD";
            }
            function f5() {
    
            }
            var e = "e"
        }
    
    </script>
    

    2.闭包的简单介绍

    闭包: 封闭+包裹

    解决问题:
    延长变量的生命周期 (变量创建-销毁)
    提供一种间接访问函数封闭空间内部数据的方法.

    需求: 需要获取a的值:

    • 01 直接返回就可以了? 解决不了.一次性的数据,如果调用多次函数返回的其实并不是同一个数据 +不能修改(设置)变量的值
    • 02 闭包解决 (把要访问的数据使用函数包裹返回)

    eg:

    <script>
    function test(){
        var a= 10;
        return a;
    }
    
    var x = test();
    console.log(x);
    var y = test();//10
    console.log(y);
    </script>
    <script>
    function test(){
        var obj = {};
        return obj;
    }
    var x = test();
    var y = test();
    console.log(x == y);//false
    </script>
    

    3.闭包获取数据以及闭包设置数据

    eg:

    <script>
    function test(){
        var a = 10;
        return function (value){
            if(value != undefined){
                a = value;
            }
            return a;
        }
    }
    
    var func = test();
    console.log(func(30));//30
    </script>
    

    闭包如何获取函数内部的多个数据?

    解决方案01

    <script>
    function test(){
        var name = '张三';
        var age = 88;
        var bookName = '未知书';
    
        return function (){
            return [name,age,bookName];
        }
    }
    
    var func = test();
    console.log(func()[0]);
    console.log(func()[1]);
    console.log(func()[2]);
    </script>
    

    解决方案2

    <script>
    function test(){
        var name = '张三';
        var age = 88;
        var bookName = '未知书';
    
        return [function (){
            return name;
        },function (){
            return age;
        },function (){
            return bookName;
        }]
    }
    
    var func = test();
    console.log(func[0]());
    console.log(func[1]());
    console.log(func[2]());
    </script>
    

    解决方案3

    <script>
    function test(){
        var name = '张三';
        var age = 88;
        var bookName = '未知书';
    
        return {
            getName:function (){
            return name;
        },
            getAge:function (){
            return age;
        },
            getBookName:function (){
            return bookName;
        },
            setName:function (nameValue){
                name = nameValue;
            },
            setAge:function (ageValue){
                age = ageValue;
            },
            setBookName:function (bookNameValue){
                bookName = bookNameValue;
            }
        }
    }
    console.log('_________________');
    var func = test();
    console.log(func.getName());
    console.log(func.getAge());
    console.log(func.getBookName());
    
    //设置数据
    func.setName('鲁迅');
    func.setAge('20');
    func.setBookName('骆驼祥子');
    console.log(func.getName());
    console.log(func.getAge());
    console.log(func.getBookName());
    </script>
    

    4.闭包的作用

    闭包的作用:

    • 01 提供一种间接访问(读写)函数内部封闭空间中数据的方法
    • 02 延长变量的生命周期
    • 03 保护数据让代码干呢更加安全和稳定 有时候在设置数据之前需要校验数据

    eg:

    <script>
    function foo(){
        var age = 0;
        return {
            getAge:function (){
                return age;
            },
            setAge:function (aT){//校验数据
                if(aT<0){
                    aT = 0;
                }
                age = aT;
            }
        }
    }
    
    var test = foo();
    test.setAge(-20);
    console.log(test.getAge());//0
    </script>
    

    5.setTimeout和闭包的执行

    定时器:

    • setTimeout :一次定时器 ,只会执行一次(延迟执行函数)

    参数:第一个参数:要执行的任务 ,第二个参数:间隔时间(单位毫秒 1000ms = 1s)

    • setInterval 每隔固定的时间就执行一次

    eg:

     <script>
        var now = new Date();
        console.log(now);
        setTimeout(function(){
            console.log('一次定时器',new Date());
        },1000);
    </script>
    <script>
        var now = new Date();
        console.log(now);
        setInterval(function(){
            console.log('多次定时器',new Date());
        },1000);
    </script>
    

    6.线程与进程等相关概念

    队列: 先进先出
    栈:先进后出(数据结构 存储结构)

    进程: 系统中正在运行的一个应用程序

    线程: 是在进程中真正执行任务的部分.一个进程中至少有一条线程,可以有多个线程;
    eg:学校-老师

    串行执行:一条线程执行多个任务,在执行的时候按照固定的顺序一个接着一个的执行

    并发执行:多条线程一起执行多个任务,同一个时间有多个任务在同时执行

    多线程:
    进程中可以有多条线程
    优点:速度快,效率高 缺点:安全性差

    主线程: 在进行开启的时候默认会创建一条线程,是主线程

    并行和并发的区别:

    并发: 多条线程同时执行任务的现象

    并行: 同时执行多个任务的能力;

    js本身是单线程

    局限性: 如果要执行多个任务,只能串行的执行任务

    js的主要任务(顺序):

    • 01 渲染任务
    • 02 脚本中的主要代码
    • 03 事件处理任务(定时器事件|点击事件等等)

    eg:

    <script>
    for(var i= 0;i<10;i++){
        //执行定时器打印
      /*  (function (j){
            setTimeout(function (){
                console.log(j);
            },0)
        })(i);*/
        setTimeout((function (j){
            return function (){
                console.log(j);
            }
        })(i),0)
    }
    </script>
    

    7.闭包在点击事件的应用

    eg:
    <body>
    <div>我是第1个div</div>
    <div>我是第2个div</div>
    <div>我是第3个div</div>
    <div>我是第4个div</div>
    <div>我是第5个div</div>
    <div>我是第6个div</div>
    <div>我是第7个div</div>
    <div>我是第8个div</div>
    <div>我是第9个div</div>
    <div>我是第10个div</div>
    <script>
        var divs = document.getElementsByTagName('div');
        for(var i = 0;i<divs.length;i++){
            var div = divs[i];
           /* (function (j){
                div.onclick = function (){
                    alert('我是第'+j+'个标签');
                }
            })(i);*/
    
            div.onclick = (function (j){
                return function (){
                    alert('我是第'+j+'个标签');
                }
            })(i);
        }
    </script>
    </body
    

    8.函数的特殊性

    函数: 可以被调用()

    1. 本质是一个对象,因此凡是可以使用对象的地方都可以使用函数,函数可以作为其他函数的参数,也可以作为其他函数的返回值
    2. 函数可以创建作用域
    3. 函数可以有自己的方法和属性

    函数的创建方法:

    • 01 函数声明 function 函数名(参数){函数体}

    • 02 表达式

      01 var func = function (){} 匿名的函数表达式

      02 var func = function name(){} 命名函数表达式

    • 03 构造函数 var func = new Function()

    注意:函数有名称:name属性

    eg:

    <script>
    var func01 = function (){};
    var func02 = function funcName(){};
    
    //注意:函数有名称:name属性
    console.log(func01.name);//func01 注意:在火狐浏览器中为空
    console.log(func02.name);//funcName
    </script>
    

    9.函数的回调(作为参数的传递)

    1. 函数作为其他函数的参数

    回调: 回过头来调用

    1. 函数是第一型对象(因此可以使用对象的地方都可以使用函数)
    • 01 函数可以作为函数的参数
    • 02 函数可以作为函数的返回值
    1. 回调函数(回调),当我们把某个参数传递给另一个函数的时候,这个函数就称为回调函数

       eg:
       <script>
           function demo(callBack){
           //其他代码
               callBack();
           };
           function foo(){
               console.log('foo!');
           }
           demo(foo);//foo!
       </script>
      

    分析代码:

    原因: 函数调用方式改变

    解决: call | apply

    eg:

    <script>
        var name = '我是测试代码';
        function demo(callBack){
            callBack();//使用回调函数
        }
        function func(){
            var name  = '张三';
            console.log('只是一个回调函数'  + this.name);
        }
        //注意点:window 有一个属性为name,并且为空.
        /*console.log(window.name);*/
    
        demo(func);//只是一个回调函数 我是测试代码
    
    
    
    </script>
    <script>
        //如果回调函数是某个对象的方法,而该对象方法中使用了this指针,那么该方法作为回调函数来使用的时候,需要注意this
        var name = '我是测试代码';
        function demo(callBack,callBackObj){
            //判断
            if(typeof callBack == 'string'){//字符串
                callBack = callBackObj[callBack];
            }
            if(typeof callBack == 'function'){//函数
                callBack.call(callBackObj);//借用callBack的方法
            }
            //其他代码
        }
    
    var obj = {
        name:'张三',
        show:function (){
            console.log('show'+ this.name);
        }
    };
    
    var o = {
        name:'李四',
        show:function (){
            console.log('show'+ this.name);
        }
    };
    
    obj.show();
    demo(obj.show,obj);//show 张三
    demo(o.show,o);
    demo('show',o);
    demo('show',obj);
    
    </script>
    

    10.函数作为返回值

    eg:
    //使用闭包实现一个计数器(在该实例中)
    //通过调用返回值(一个函数)
    
    <script>
        function countF(){
            var count = 0;
            return function (){
                return count++;
            }
        }
        var next = countF();
        console.log(next());
        console.log(next());
        console.log(next());
        console.log(next());
        console.log(next());
        console.log(next());
    </script>
    

    11.自定义函数(惰性函数)

    惰性函数定义:

    • 特点是在第二次调用函数的时候这个函数才被正确的定义;第一次调用函数的时候只是做了一些初始化的处理
    • 特征:可以实现函数的自我更新

    注意点:

    • 01 实现自我更新之后函数上面的属性会丢失
    • 02 把函数赋值给变量或者是对象的方法之后,以变量或者是对象的方法来调用函数的时候,不会实现自我更新

    eg:

    <script>
    function foo(){
        console.log('foo!');
        //初始化操作
    
        foo = function (){
            console.log('foo!','foo!');
        }
    }
    foo.des = 'foo的描述信息';
       /* foo();//foo!
        foo();//foo! foo!
        foo();//foo! foo!*/
        console.log(foo.des);//undefined
    
    var demo = foo;
    var obj = {};
    obj.show = foo;
    demo();//foo!
    demo();//foo!
    demo();//foo!
    console.log('+++++++++++');
    foo();//foo! foo!
    obj.show();//foo!
    obj.show();//foo!
    obj.show();//foo!
    </script>
    

    12.即时函数的补充以及初始化

    基本写法[2]:

    即时函数组成:

    • 001 函数(函数体 + function + 参数 + 返回值)
    • 002 ()包住函数
    • 003 ()调用函数

    其他的写法:! + _ ~

    即时函数可以接受参数也可以返回数据

    eg:

    <script>
    //01第一种写法
    /*(function (){
        console.log('第一种写法');
    })()
    
    //02第二种写法
    (function (){
        console.log('第二种写法');
    }())
    
    //03 其他写法
    !(function (){
        console.log('不建议的演示');
    })();
    
    +(function (){
        console.log('不建议的演示');
    })();
    
    -(function (){
        console.log('不建议的演示');
    })();
    
    ~(function (){
        console.log('不建议的演示');
    })();*/
    
    var result = (function (string){
        var str = 'hello'+ string;
        console.log(str);
        return str;
    })('demo');
    console.log(result);
    </script>
    

    即时对象初始化

    写法:

    • 01 提供一个对象{}属性和方法
    • 02 在对象中提供一个初始化的方法,主要做一些初始化操作
    • 03 在对象外部添加(),包装成一个表达式
    • 04 直接使用.init()来进行初始化处理

    eg:

    <script>
    ({
        name:'张三',
        age:99,
        showName:function (){
            console.log(this.name);
        },
        showAge:function (){
            console.log(this.age);
        },
        init:function (){
            //初始化处理
            this.showName();
            this.showAge();
        }
    }).init();
    console.log(name);//空
    console.log(age);//报错
    

    #### 二.设计模式的简单介绍

    1. 设计模式:

    • 设计模式本身是一种解决特定问题的套路
    • 设计模式的分类:23种
    • 设计模式的来源于建筑学邻域
    • 设计模式的由来:四人帮(设计模式)

    列举:单利模式 | 代理模式 |观察者模式 |工厂模式 | 策略模式 | 桥接模式 ......

    2.工厂模式的说明

    核心过程:

    • 01 提供父构造函数
    • 02 设置父构造函数的原型对象(属性|方法) 目的的共享
    • 03 为父构造函数提供一个静态工厂方法(每次要生产产品就调用这个方法)
      1. 001 接收产品的类型
      2. 002 判断是否支持生产该类型的产品
      3. 003 设置原型继承,获得原型对象上面的方法
      4. 004 生产该类型的一个产品
      5. 005 返回对象
    • 04 定制合作伙伴(子构造函数)
    • 05 调用父构造函数的工厂函数来创建对象

    eg:

    <script>
        //01 提供父构造函数
        function MakePhone(){};
        //02 设置父构造函数的原型对象(属性|方法)  目的的共享
        MakePhone.prototype.desLog = function (){
            console.log('我的广告是:' + this.des);
        };
    
        //03 为父构造函数提供一个静态工厂方法(每次要生产产品就调用这个方法)
        MakePhone.factory = function (stringType){
            //001 接收产品的类型
            var phoneType = stringType;
            if(phoneType == undefined){
                throw '请下订单';
            }
            //002 判断是否支持生产该类型的产品
            if(typeof MakePhone[phoneType] != 'function'){
                throw '和该品牌没有任何的合作关系,不支持生产';
            };
            //003 设置原型继承,获得原型对象上面的方法
            MakePhone[phoneType].prototype = MakePhone.prototype;
            //004 生产该类型的一个产品
            var newPhone = new MakePhone[phoneType]();
    
            //005返回对象
            return newPhone;
    
        };
        //04 定制合作伙伴(子构造函数)
        MakePhone.iphone = function (){
            this.des = '最贵的手机,最垃圾的系统';
        };
        MakePhone.vivo = function (){
            this.des = '充电五分钟,通话两小时';
        };
        MakePhone.oppo = function (){
            this.des = '照亮你的美';
        };
        //05调用父构造函数的工厂函数来创建对象
        var iphone = MakePhone.factory('iphone');
        iphone.desLog();
        var oppo = MakePhone.factory('oppo');
        oppo.desLog();
        var vivo = MakePhone.factory('vivo');
        vivo.desLog();
        </script>

    相关文章

      网友评论

          本文标题:面向对象之闭包及设计模式的简单介绍day06

          本文链接:https://www.haomeiwen.com/subject/hddpnttx.html