zoukankan      html  css  js  c++  java
  • js学习总结----设计模式

    一、单例模式

      对象数据类型的作用

      把描述同一个事物(同一个对象)的属性和方法放在一个内存空间下,起到了分组的作用,这样不同事物之间的属性即使属性名相同 ,相互也不会发生冲突

      我们把这种分组编写代码的模式叫做"单例模式"

      在单例模式中我们把person1或者person2也叫做"命名空间"

            var person1 = {
                name:'张三',
                age:18
            }
    
            var person2 = {
                name:"李四",
                age:34
            }            

      单例模式是一种项目开发中经常使用的模式,因为项目中我们可以使用单例模式来进行我们的"模块化开发"

      模块化开发:对于一个相对来说比较大的项目,需要多人协作的开发的,我们一般情况下会根据当前项目的需求划分成几个功能模块,每个人负责一部分,同时开发,最后把每个人的代码进行合并。

         var utils = {
                select:function(){
    
                }
            }
            var searchRender = {
                change:function(){
                    utils.select();//调用外部的方法
                    this.clickEven();
                },
                clickEven:function(){
                    
                }
            }

    二、工厂模式

      单例模式虽然解决了分组的作用,但是不能实现批量的生产,属于手工作业模式,所以出现了工厂模式

      把实现同一件事情的代码放到一个函数中,以后如果再想实现这个功能,不需要重新的编写这些代码了,只需要执行当前的函数即可->函数的封装

      低耦合高内聚:减少页面中的冗余代码,提高代码的重复利用率

        function createJsPerson(name,age){
                var obj = {};
                obj.name = name;
                obj.age = age;
                obj.writeJs = function(){
                    console.log('ok')
                }
                return obj;
            }
            var p1 = createJsPerson("小王",12);

        js是一门轻量级的脚本“编程语言”(html+css不属于编程语言,属于标记语言)

        所有的编程语言都是面向对象开发的->类的继承、封装、多态。

        继承:子类继承父类中的属性和方法

        多态:当前方法的多种形态  后台语言中:多态包含重载和重写(重载:方法名相同,参数类型不同)

         js中不存在重载,方法名一样的话,后面的会把前面的覆盖掉,最后只保留一个

         js中有一个操作类似重载但是不是重载:我们可以根据传递的参数不一样,实现不同的功能。    

         function sum(num){
                if(typeof num === "undefined"){
                    return 0
                }
                return num
            }
            sum(100);
            sum()

        重写:子类重写父类的方法

    三、构造函数模式

      构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例

      构造函数模式和工厂模式的区别:

      1、执行的时候

      普通函数执行->createJsPerson()

      构造函数模式->new CreateJsPerson() 通过new执行后,我们的CreateJsPerson就是一个类,而函数执行的返回值(p1)就是CreateJsPerson()这个类的一个实例

      2、在函数代码执行的时候

      相同:都是形成一个私有的作用域,然后形参赋值->预解释->代码从上到下执行(类和普通函数一样,他也有函数的一面)

      不同:在代码执行之前,不用自己在手动的创建obj对象了,浏览器会默认的创建一个对象数据类型的值,这个对象其实就是我们当前类的一个实例,接下来代码从上到下执行,以当前的实例为执行的主体(this代表的就是当前的实例),然后分别的把属性名和属性值赋值给当前的实例。浏览器会默认的把创建的实例返回。

        function CreateJsPerson(name,age){
           //浏览器默认创建的对象就是我们的实例p1 -> this
    this.name = name; this.age = age; this.writeJs = function(){ console.log('ok') } }
        var p1 = new CreateJsPerson('张三',12);
        var p2 = new CreateJsPerson('李四',13);
        
        var res = CreateJsPerson("类似",7);//这样写不是构造函数模式执行而是普通的函数执行 由于没有写return 所以res = undefined
        并且CreateJsPerson这个方法中的this是window
     

      创建一个数组:

      var ary = [];//字面量方式

      var ary = new Array();//实例创建的方式->构造函数模式执行的方式

      不管哪一种方式ary都是Array这个类的实例

      注意:

      js中所有的类都是函数数据类型的,它通过new执行变成了一个类,但是它本身也是一个普通的函数。

      js中的所有的实例都是对象数据类型的

      在构造函数模式中,类中(函数体中)出现的this.xxx = xxx中的this是当前类的一个实例

      虽然p1和p2都是CreateJsPerson这个类的实例,所以都拥有writeJs这个方法,但是不同实例之间的方法是不一样的。

      在类中给实例增加的属性(this.xxx = xxx)属于当前实例的私有的属性,实例和实例之间是单独的个体,所以私有的属性之间是不相等的。

      扩展代码如下:

    function Fn(){
                var num = 10;
                this.x = 100;
                this.getX = function(){
                    //this->需要看getX执行的时候才知道
                    console.log(this.x)
                }
            }
            var f1 = new Fn;
            var f2 = new Fn;
            f1.getX();// this 是f1 ->100
            var ss = f1.getX;
            ss()//this 代表window ->undefined
            console.log(f1.num)//undefined
            /*
            1、在构造函数模式中new Fn()执行,如果Fn不需要传递参数的话,后面的小括号可以省略
            2、this的问题:在类中出现的this.xxx = xxx中的this都是当前类的实例,而某一个属性值(方法),方法中的this需要看方法执行的时候,前面是否有".",才知道this是谁
            3、类有普通函数的一面,当函数执行的时候,var num其实只是当前形成的私有作用域的私有变量而已,它和我们的f1这个实例没有任何的关系,只有this.xxx = xxx 才相当于给f1这个实例增加私有的属性和方法,才和我们的f1有关系...
            4、在构造函数模式中,浏览器会默认的把我们的实例返回(返回的是一个对象数据类型的值);如果我们自己手动写了return 返回:
                返回的是一个基本数据类型的值,当前实例是不变的,例如:return 100。我们的f1还是当前Fn的实例
                返回的是一个引用数据类型的值,当前的实例会被自己返回的值替换掉,例如:return{name:'李四'}我们的f1就不在是Fn的实例了,而是对象{name:'李四'}
            5、检测某一个实例是否属于这个类->instanceof
                console.log(f1 instanceof Fn)//true
                console.log(f1 instanceof Array)//false
                console.log(f1 instanceof Object)//true 因为所有的实例都是对象数据类型的,而每一个对象数据类型都是Object这个内置类的一个实例,所以f1也是它的一个实例
                对于检测数据类型来说,typeof有自己的局限性,不能细分object下的对象、数组、正则...
            6、f1和f2都是Fn这个类的一个实例,都拥有x和getX两个属性,但是这两个属性是各自私有的属性,所以:
            console.log(f1.getX===f2.getX);//false
            7、in:检测某一个属性是否属于这个对象 attr in object ,不管是私有的属性还是公有的属性,只要存在,用in来检测都是true
               console.log('getX' in f1)// true
               hasOwnProperty:用来检测某一个属性是否为这个对象的"私有"属性,这个方法只能检测私有的属性
               console.log(f1.hasOwnProperty('getX'))// true
         8、isPrototypeOf:函数用于指示对象是否存在于另一个对象的原型链中。如果存在,返回true,否则返回false 思考:检测某一个属性是否为该对象的"公有属性" function hasPubProperty(obj,attr){ return (attr in obj) && !obj.hasOwnProperty(attr) }
    */

    四、原型链模式

      构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立开的->实例识别

      基于构造函数模式的原型模式解决了 方法或者属性公有的问题 ->把实例之间相同的属性和方法提取成公有的属性和方法 ->想让谁公有就把它放在CreateJsPerson.prototype上即可。

      1、每一个函数数据类型(普通函数、类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值

      2、并且在prototype上浏览器天生给它加了一个属性constructor(构造函数),属性值是当前函数(类)本身

      3、每一个对象数据类型(普通的对象、实例、prototype...)也天生自带一个属性:__proto__(两个下划线),属性值是当前实例所属类的原型(prototype

         function Fn(){
                this.x = 100
           this.sum = function(){
           }
    } Fn.prototype.getX = function(){ console.log(this.x); }      Fn.prototype.sum = function(){} var f1 = new Fn; var f2 = new Fn; console.log(Fn.prototype.constructor===Fn)// true

      下面结合图来理解这三句话

      注意:

        object是JS中所有对象数据类型的基类(最顶层的类)

        1、f1 instanceof object ->true 因为f1通过__proto__可以向上级查找,不管有多少级,最后总能找到Object

        2、在Object.prototype上没有__proto__这个属性

        3、原型链模式

          f1.hasOwnProperty('x');// ->hasOwnProperty是f1的一个属性

          但是我们发现在f1的私有属性上并没有这个方法,那如何处理的呢?

          通过对象名.属性名的方式获取属性值的时候,首先在对象的私有属性上进行查找,如果私有中存在这个属性,则获取的是私有的属性值。如果私有的没有,则通过__proto__找到所属类的原型(类的原型上定义的属性和方法都是当前实例的公有的属性和方法),原型上存在的话,获取的是公有的属性值,如果原型上也没有,则继续通过原型上的__proto__继续向上查找,一直找到Object.prototype 为止...

        这种查找的机制就是我们的"原型链模式"

        f1.getX === f2.getX ->true

        f1.__proto__.getX ===f2.getX->true

        f1.getX === Fn.prototype.getX -> true

        f1.sum === f2.__proto__.sum ->false

        f1.sum === Fn.prototype.sum ->false

      在ie浏览器中,我们原型模式也是同样的原理,但是ie浏览器怕你通过__proto__把公有的修改,禁止我们使用__proto__

      扩展代码:

    /*
            在原型模式中,this常用的有两种情况
            在类中this.xxx = xxx;this->当前类的实例
            某一个方法中的this->看执行的时候"."前面是谁this就是谁
                1、需要先确定this的指向(this是谁)
                2、把this替换成对应的代码
                3、按照原型链查找,得出结果
            */
            function Fn(){
                this.x = 100;
                this.y = 200;
                this.getY = function(){
                    console.log(this.y)
                }
            }
            Fn.prototype = {
                constructor:Fn,
                y:300,
                getX:function(){
                    console.log(this.x)
                },
                getY:function(){
                    console.log(this.y)
                }
            }
    
            var f = new Fn
            f.getX();//100
            f.__proto__.getX();//undefined  console.log(f.__proto__.x)
            //在内置类的原型上扩展我们的方法: 数组去重
            Array.prototype.myUnique = function(){
                //this->ary
                var obj = {}
                for(var i = 0;i<this.length;i++){
                    var cur = this[i];
                    if(obj[cur] == cur){
                        this[i] = this[this.length-1];
                        this.length--;
                        continue
                    }
                    obj[cur] = cur;
                }
                obj = null;
                return this;//目的为了实现链式写法
            }
            //链式写法:执行完成数组的一个方法可以紧接着执行下一个方法
            //原理:ary为什么可以使用sort方法:因为sort是Array.prototype上的公有的方法,而数组ary是Array的一个实例,所以ary可以使用sort方法->数组才能使用我们Array原型上定义的属性和方法。
            //sort执行完成的返回值是一个排序后的"数组",可以执行reverse
            //reverse执行完成的返回值是一个排序后的"数组",可以执行pop
            //pop执行完成的返回值是删除的数据,不是一个数组了
            ary.sort(function(a,b){
                return a - b;
            }).reverse().pop();

      扩展-批量设置公有属性 

    //1、起一个别名
            function Fn(){
                this.x = 100;
            }
            var pro = Fn.prototype;//把原来原型指向的地址赋值给pro,现在他们操作的是同一个内存空间
            pro.getX = function(){
    
            }
            pro.getY = function(){
                
            }
            pro.getZ = function(){
                
            }
            //2、重构原型对象的方法->自己新开辟一个堆内存,存储我们公有的属性和方法,把浏览器原来给Fn.prototype开辟的那个替换掉
            function Fn(){
                this.x = 100;
            }
            Fn.prototype = {
                constructor:Fn,
                a:function(){
    
                },
                b:function(){
    
                }
            }
            var f = new Fn()
            //1、只有浏览器天生给Fn.prototype开辟的堆内存里面才有constructor,而我们自己开辟的这个堆内存没有这个属性,这样constructor指向就不在是Fn而是Object了
            console.log(f.constructor)//没做任何处理之前
            //为了和原来的保持一致,我们需要手动的增加constructor的指向
            //2、用这种方式给内置类增加公有的属性
            //给内置类Array增加数组去重的方法
            Array.prototype.unique = function(){
    
            }
            Array.prototype = {
                constructor:Array,
                unique:function(){
    
                }
            }
            console.log(Array.prototype);
            //我们这种方式会把之前已经存在于原型上的属性和方法给替换掉,所以我们用这种方式修改内置类的话,浏览器会给屏蔽掉的
            //但是我们可以一个个的修改内置的方法,当我们通过下述方式在数组的原型上增加方法,如果方法名和原来内置的重复,会把内置的修改掉-->我们以后再内置类的原型上增加方法,命名都需要加特殊的前缀
            Array.prototype.sort = function(){
                console.log('ok')
            }
  • 相关阅读:
    django 项目需要注意的一些点
    VUE之路
    Oracle 表格碎片的查看方法
    RHEL 6.x or 7.x 使用分区绑定ASM 磁盘的方法
    RMAN 修复主库 nologging 操作导致物理备库的坏块
    Oracle 数据库19c 回退降级到 11.2.0.4 方案
    如何评估oracle 数据库rman全备和增量备份大小
    在将Oracle GI和DB升级到19c或降级到以前的版本之前需要应用的补丁 (Doc ID 2668071.1)
    Oracle 数据库坏块处理
    opatch auto 安装11.2.0.4.20190115 PSU遇到 OUI-67133: Execution of PRE script failed,with returen value 1 报错
  • 原文地址:https://www.cnblogs.com/diasa-fly/p/7081616.html
Copyright © 2011-2022 走看看