JavaScript之定义类或对象六种方式

1、工厂方式

     //类的定义

    function createCar(){
                 var oTempCar = new Object;
                 oTempCar.color = 'red';
                 oTempCar.doors = 4;
                 oTempCar.mpg = 23; //时速
                 oTempCar.showColor = function(){
                 alert(this.color);
        };
        return oTempCar;
    }

    //对象创建
    var car1 = new createCar();
    var car2 = new createCar();

    //也可以定义带参数的类
    function createCar(iColor, iDoors, iMpg){
                 var oTempCar = new Object;
                 oTempCar.color = iColor;
                 oTempCar.doors = iDoors;
                 oTempCar.mpg = iMpg; //时速
                 oTempCar.showColor = function(){
                 alert(this.color);
        };
        return oTempCar;
    }

    //对象创建
    var car1 = new createCar('red', 4, 23);
    var car2 = new createCar('blue', 3, 25);
         前面的例子中,每次调用函数createCar(),都要闯建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象都共享了同一个函数。为了避开此问题,可以采用在工厂函数外定义对象的方法;

    function showColor(){
        alert(this.color);
    };

    function createCar(iColor, iDoors, iMpg){
                 var oTempCar = new Object;
                 oTempCar.color = iColor;
                 oTempCar.doors = iDoors;
                 oTempCar.mpg = iMpg; //时速
                 oTempCar.showColor = showColor;
                 return oTempCar;
    }

    var car1 = new createCar('red', 4, 23);
    var car2 = new createCar('blue', 3, 25);
    car1.showColor(); //outputs 'red'
    car2.showColor(); //outputs 'blue'
        尽管上述方法从功能上解决了多次创建函数的问题,但该函数看起来不像是对象的方法。所有这些问题引发了开发者定义的构造函数的出现。

2、构造函数方式

     创建构造函数第一步选择类名,即构造函数的名字,这个名字的首字母大写。以使它与字母通常是小写的变量名区分开。

         function Car(iColor, iDoors, iMpg){
                  this.color = iColor;
                  this.doors = iDoors;
                  this.mpg = iMpg;
                  this.showColor = function(){
                  alert(this.color);
        };
    }

    var car1 = new createCar('red', 4, 23);
    var car2 = new createCar('blue', 3, 25);

可以看出其与工厂方式存在以下区别:
a.构造函数内部无创建对象,而是使用this关键字。
b.使用new运算符调用构造函数是,在执行第一行代码前先创建一个对象,只有用this才能访问该对象。然后可以直接赋予this属性,默认情况下是构造函数的返回值。但是构造函数方式与工厂方式一样,会重复生成函数,为每个对象都创建独立的函数版本。

3、原型方式

        该方式利用了对象的prototype对象,可把它看成创建新对象所依赖的原型。
        这里用空构造函数来设置类名,然后所有的属性和方法都没直接赋予prototype属性。重写前面的例子代码如下:

    function Car(){}
         Car.prototype.color = 'red';
         Car.prototype.doors = 4;
         Car.prototype.mpg = 23;
         Car.prototype.showColor = function(){
        alert(this.color);
    };

    var car1 = new Car();
    var car2 = new Car();

         在这段代码中,首先定义构造函数Car(),接下来的几行代码,通过给Car的prototype属性添加属性去定义Car对象的属性。调用new Car()是,原型的所有属性都被立即赋予要创建的对象,意味着所有Car实例存放的都是指向showColor()函数的指针。从语义上将,所有属性看起来都属于一个对象,以此解决了前面两种方式存在的问题。此外,使用该方法,还能instanceof运算符检查给定变量指向的对象的类型。因此,下面的代码将输出true:alert(car1 instanceof Car); //outputs 'true'看起来是个非常好的解决方案。遗憾的是,它并不尽如人意。首先,这个构造函数没有参数。使用原型方式时不能通过构造函数传递参数初始化对象属性。真正的问题并不在这里,而是出现在属性指向的是对象,而不是函数时。函数共享是不会出现问题的,但对象却很少是被多个实例共享的。

例如:

    function Car(){}
         Car.prototype.color = 'red';
         Car.prototype.doors = 4;
         Car.prototype.mpg = 23;
         Car.prototype.drivers = new Array('Mike', 'Sue');
         Car.prototype.showColor = function(){
         alert(this.color);
    };

    var car1 = new Car();
    var car2 = new Car();   
    car1.drivers.push('Mart');
    alert(car1.drivers); //outputs 'Mike, Sue,Mart'
    alert(car2.drivers); //outputs 'Mike, Sue,Mart'

         这里,属性drivers是指向Array对象的指针,该数组中包含两个名字'Mike'和'Sue'。由于drivers是引用值,Car的两个实例都指向同一个数组。这意味着car1.drivers添加值'Matt',在car2.drivers中也能看到。输出这两个指针中的任何一个,结果都是现实字符串'Mike, Sue,Mart'。那么该如何解决以上提出的问题呢?

 4、混合的构造函数/原型方式

        用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法),所有函数都只创建一次,而每个对象都具有自己的对象属性实例。

                   function Car(iColor, iDoors, iMpg){
                           this.color = iColor;
                           this.doors = iDoors;
                           this.mpg = iMpg;
                           this.drivers = new Array('Mike', 'Sue');
                   }

                 Car.prototype.showColor = function(){
                 alert(this.color);
        };

        var car1 = new createCar('red', 4, 23);
        var car2 = new createCar('blue', 3, 25);   
        car1.drivers.push('Mart');   
        alert(car1.drivers); //outputs 'Mike, Sue,Mart'
        alert(car2.drivers); //outputs 'Mike, Sue'

         所有的非函数属性都在构造函数中创建,意味着又可以用构造函数的参数赋予属性默认值了。

5、动态原型方式

         动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内部室非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。

function Car(iColor, iDoors, iMpg){
        this.color = iColor;
        this.doors = iDoors;
        this.mpg = iMpg;
        this.drivers = new Array('Mike', 'Sue');
         if(typeof Car._initialized == 'undefined'){
            Car.prototype.showColor = function(){
              alert(this.color);
           };
            Car._initialized = true;
         }
    }

         简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,更符合其他语言中类的定义了。

6、混合工厂方式

         它的目的是创建假构造函数,只返回另一种对象的新实例。

         function Car(){
                     var oTempCar=new Object;
                     oTempCar.color=”red”;
                     oTempCar.doors=4;
                     oTempCar.mpg=23;
                     oTempCar.showColor=function(){
         alert(this.color);
};
return oTempCar;
}

      由于在Car()构造函数内部调用了new运算符,所以将忽略第二个new运算符(位于构造函数之外)。在构造函数内部创建的对象被传递回变量var。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值