您现在的位置: 万盛学电脑网 >> 程序编程 >> 脚本专题 >> javascript >> 正文

JavaScript定义类的几种方式总结

作者:佚名    责任编辑:admin    更新时间:2022-06-22

 本篇文章主要是对JavaScript定义类的几种方式进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助

提起面向对象我们就能想到类,对象,封装,继承,多态。在《javaScript高级程序设计》(人民邮电出版社,曹力、张欣译。英文名字是:Professional JavaScript for Web Developers)这本书中描述的还算比较详细。我们看看JavaScript中定义类的各种方法。    1.工厂方式   javaScript中创建自己的类和对象,我们应该是必须掌握的,我们都知道javaScript中对象的属性可以在对象创建后动态定义,比如下面的代码:    代码如下: <script type="text/javascript">     //定义     var oCar = new Object();     oCar.color = "red";     oCar.doors = 4;     oCar.showColor = function() {         alert(this.color);     }     //调用     oCar.showColor(); </script>    我们很容易使用oCar对象,但是我们创就是想创建多个Car实例。我们可以使用一个函数来封装上面的代码来实现: 复制代码 代码如下: <script type="text/javascript">     //定义     function createCar() {         var oCar = new Object();         oCar.color = "red";         oCar.doors = 4;         oCar.showColor = function() {             alert(this.color);         }         return oCar;     }     //调用     var ocar1 = createCar();     var ocar2 = createCar();     ocar1.color = "black";     ocar1.showColor();     ocar2.showColor(); </script>   顺便说一下,javaScript对象默认成员属性都是public 的。这种方式我们称为工厂方式,我们创造了能创建并返回特定类型的对象的工厂。   这样做有点意思了,但是在面向对象中我们经常使用创建对象的方法是:   Car car=new Car();   使用new 关键字已经深入人心,因此我们使用上面的方法去定义总感觉别扭,并且每次调用时都去创建新的属性以及函数,功能上也不实际。下来我们看看构造函数的形式定义类。   2.构造函数   这种方式看起来有点象工厂函数。具体表现如下:  代码如下: <script type="text/javascript">     //定义     function Car(color, doors) {         this.color = color;         this.doors = doors;         this.showColor = function() {             alert(this.color);         };     }     //调用     var car1 = new Car("red", 4);     var car2 = new Car("blue", 4);     car1.showColor();     car2.showColor(); </script>    看起来效果很明显,有差别了吧。感觉有点意思了。在构造函数内部创造对象使用this 关键字,使用new 运算符创建对象感觉非常亲切。但是也有点问题:每次new 对象时都会创建所有的属性,包括函数的创建,也就是说多个对象完全独立,我们定义类的目的就是为了共享方法以及数据,但是car1对象与car2对象都是各自独立的属性与函数,最起码我们应该共享方法。这就是原形方式的优势所在。   3.原型方式   利用对象的prototype属性,可把它看出创建新对象所依赖的原型。方法如下:   代码如下: <script type="text/javascript">     //定义     function Car() {     };     Car.prototype.color = "red";     Car.prototype.doors = 4;     Car.prototype.drivers = new Array("Tom", "Jerry");     Car.prototype.showColor = function() {         alert(this.color);     }     //调用:     var car1 = new Car();     var car2 = new Car();     car1.showColor();     car2.showColor();     alert(car1.drivers);     car1.drivers.push("stephen");     alert(car1.drivers); //结果:Tom,Jerry,stephen     alert(car2.drivers); //结果:Tom,Jerry,stephen       //可以用json方式简化prototype的定义:           Car.prototype =         {             color: "red",             doors: 4,             drivers: ["Tom", "Jerry",'safdad'],             showColor: function() {                 alert(this.color);             }         } </script>     首先这段代码的构造函数,其中没有任何代码,接下来通过对象的prototype属性添加属性定义Car对象的属性。这种方法很好,但是问题是Car的对象指向的是Array指针,Car的两个对象都指向同一个Array数组,其中一个对象car1改变属性对象的引用(数组Array)时,另一个对象car2也同时改变,这是不允许的。   同时该问题也表现在原型不能带任何初始化参数,导致构造函数无法正常初始化。这需要另一种方式来解决:那就是混合的构造函数/原型模式。   4. 混合的构造函数/原型模式   联合使用构造函数和原型方式,定义类就非常方便。   代码如下: <script type="text/javascript"> //定义     function Car(color,doors)    {         this.color=color;         this.doors=doors;         this.drivers=new Array("Tom","Jerry");    }      Car.prototype.showColor=function(){         alert(this.color);    }      //调用:    var car1=new Car('red',4);    var car2=new Car('blue',4);      car1.showColor();    car2.showColor();      alert(car1.drivers);    car1.drivers.push("stephen");    alert(car1.drivers); //结果:Tom,Jerry,stephen    alert(car2.drivers); //结果:Tom,Jerry    alert(car1 instanceof Car);   </script>     该方法是把属性放在内部定义,把方法放在外边利用prototype进行定义。解决了第三种方法的问题。   这种方法其实应该来说非常友好了,但是比起java的语法来,应该有一些不和谐,感觉比较凌乱,对C++来说,我们就没有那么麻烦的感觉了,可是开发C++的研发人员一般情况下很少涉及javaScript,而对J2EE的研发人员来说,这种方式总有一些别扭。总感觉不是友好的封装,其实只不过是视觉上封装效果不是很好而已,要想达到视觉封装效果而又能达到这种方法的效果的也可以以,个人认为其实比较麻烦。那就是动态原型法。   5.动态原型   对于习惯使用其他语言的开发者来说,使用混合的构造函数/原型方式感觉不那么和谐。毕竟,定义类时,大多数面向对象语言都对属性和方法进行了视觉上的封装。考虑下面的C#类:  代码如下: class Car //class {     public string color = "red";     public int doors = 4;     public int mpg = 23;       public Car(string color, int doors, int mpg) //constructor     {         this.color = color;         this.doors = doors;         this.mpg = mpg;     }     public void showColor() //method     {         Console.WriteLine(this.color);     } }     C#很好的打包了Car类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,它定义了一个对象的信息。批评混合的构造函数/原型方式的人认为,在构造函数内存找属性,在其外部找方法的做法不合逻辑。因此,他们设计了动态原型方法,以提供更友好的编码风格。   动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的Car类:    代码如下:     <script type="text/javascript">