美文网首页前端交流圈
JavaScript——创建对象的模式(一)

JavaScript——创建对象的模式(一)

作者: lulu_c | 来源:发表于2019-04-30 17:49 被阅读20次

    最近了解了几种创建对象的模式,下面总结一下它们的区别。

    • 工厂模式
    • 构造函数模式
    • 原型模式
    • 组合构造函数模式和原型模式
    • 动态原型模式
    • 寄生构造函数模式
    • 稳妥构造函数模式

    工厂模式

    用函数封装以特定接口创建对象的细节。

    function a (name) {
        var obj = new Object();
        obj.name = name;
        obj.hello = function () {
              alert("hello "+this.name);
        };
        return obj;
    }
    
    var a1 = a("one");
    var a2 = a("two");
    

    工厂模式解决了创建多个相似对象的问题,但是无法知道对象的类型。

    构造函数模式

    构造函数可以创建指定类型的对象。创建自定义的构造函数可以创建自定义对象的属性和方法。

    function A (name) {
        this.name = name;
        this.hello = function () {
              alert("hello "+this.name);
        };
    }
    var a1 = new A("one");
    var a2 = new A("two");
    

    这里遵循构造函数命名规则第一个字母要大写,与工厂模式相比,构造函数模式没有显式创建对象,直接把属性和方法赋给this对象,同时也没有返回对象,在创建A对象时要使用new,这种方式的过程:1.创建一个新对象 2. 将构造函数的作用域赋给新对象(this指向这个对象)3.执行构造函数(新对象添加属性方法)4.返回对象。

    a1和a2分别保存着A的一个不同的实例,两个对象里都有一个constructor(构造函数)属性指向A

    alert(a1.contructor == A);//true
    alert(a2.contructor == A);//true
    

    检测对象类型最后还是用instanceof,a1、a2也是Object的实例。

    alert(a1 instanceof A);//true
    alert(a1 instanceof Object);//true
    

    以这种方式定义的构造函数是定义在Global对象(在浏览器是window对象)的。

    1.将构造函数当作函数
    构造函数与其他函数的区别在于调用方式不同,任何函数,只要通过new调用就可以作为构造函数,不通过new调用就跟普通函数一样

    //当作构造函数
    var a = new A("one");
    a.hello();//“hello one”
    //普通函数
    A("one");//添加到window
    window.hello();//"hello one"
    //在另一个对象的作用域中调用
    var obj = new Object();
    A.call(obj,"one");
    obj.hello();//"hello one"
    

    2.构造函数的问题
    构造函数的问题就是每个方法都要在每个实例上重新创建一遍,a1、a2都有hello方法,但是两个方法不是同一个实例。函数也是对象,实例化函数也是实例化对象。也就是说a1和a2的hello方法并不相等。创建两个相同任务的function实例没有必要,而且有this对象,并不用在执行代码前就把函数绑定在特定对象上。

    function A (name) {
        this.name = name;
        this.hello = hello;
    }
    function hello () {
          alert("hello "+this.name);
    }
    var a1 = new A("one");
    var a2 = new A("two");
    

    这样a1、a2 对象共享了在全局作用域定义的同一个hello()函数,解决了两个函数做同一件事的问题,但是这个全局函数只被某个对象调用,不符合全局的说法。而且如果方法很多,就要定义很多全局函数,那我们自定义的类型就没有封装性了。

    原型模式

    每个函数都有一个prototype属性,是一个指向对象的指针,使用这个属性我们就不必在构造函数中定义对象的实例信息,可以将这些信息直接添加到原型对象中。

    function A(){
    }
    A.prototype.name = "张三";
    A.prototype.hello = function(){    
     alert("hello " + this.name);
    }
    
    var a1 = new A();
    
    a1.hello();      //"张三"
    var a2= new A();
    
    a2.hello();      //"张三"
    alert(a1.hello == a2.hello);//true
    

    属性和方法都添加在原型上,构造函数实为空函数,与纯构造函数创建的对象不同,这些属性和方式都是公用的(单例模式)这个是优点也是缺点,函数和基本值属性共享很好,但是如果是引用属性就有问题了。

    function A(){}
    A.prototype = {    
       constructor:A,    
       name:"张三",   
       cwu:["cat","dog"],    
       hello:function(){ 
          alert("hello " + this.name);  
       }
     }
    var a1= new A();
    var a2= new A(); 
    a1.cwu.push("fish");
    console.log(a1.cwu);   //["cat","dog","fish"]
    console.log(a2.cwu);   //["cat","dog","fish"]
    console.log(a1.cwu=== a2.cwu);   //true
    

    因为共享,改变其中一个的实例就会改变全部的实例。

    组合构造函数模式和原型模式

    结合两者优点,这种模式也是比较常用的。既存在公共属性和方法,又可以自带私有参数

    function A(name){     
       this.name = name; 
       this.cwu = ["cat","dog"];
    }
    A.prototype = {    
        constructor:A,     
         hello:function(){ 
          alert("hello " + this.name);  
       }
    }
    
    var a1= new A("张三");
    var a2= new A("哈哈");
    a1.cwu.push("fish");
    
    console.log(a1.cwu);   //["cat","dog","fish"]
    console.log(a2.cwu);   //["cat","dog"]
    
    console.log(a1.cwu=== a2.cwu);   //false
    console.log(a1.hello === a2.hello);   //true
    

    相关文章

      网友评论

        本文标题:JavaScript——创建对象的模式(一)

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