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">
        //定义
        function Car() {
            this.color = "red";
            this.doors = 4;
            this.drivers = new Array("Tom", "Jerry");
            if (typeof Car._initialized == "undefined") {
                Car.prototype.showColor = function() {
                    alert(this.color);
                }
                //............
            }
            //最后定义
            Car._initialized = true;
        }
    </script>
直到检查typeof Car._initialized是否等于"undefined"之前,这个构造函数都未发生变化。这行代码是动态原型方法中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把Car._initialized设置为true。如果这个值定义了(它的值为true时,typeof的值为Boolean),那么就不再创建该方法。简而言之,该方法使用标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,为取悦传统的OOP开发者,这段代码看起来更像其他语言中的类定义了。
6  混合工厂方式

这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。这段代码看来与工厂函数非常相似:
function Car() {
            var oTempCar = new Object();
            oTempCar.color="red";
            oTempCar.doors=4;
            oTempCar.mpg=23;
            oTempCar.showColor = function() {
                alert(this.color);
            }
            return oTempCar;
        }
与经典方式不同,这种方式使用new运算符,使它看起来像真正的构造函数:
var oCar = new Car();

由于在Car()构造函数内部调用了new运算符,所以将忽略第二个new运算符(位于构造函数之外)。在构造函数内部创建的对象被传递回变量var。这种方式在对象方法的内部管理方面与经典方式有着相同的问题。强烈建议:除非万不得已(请参阅第15章),还是避免使用这种方式。
总结:(采用哪种方式)
目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。
//ps
//static class (1:function)
    var CarCollection = new function() {
        var _carCollection = new Array(); //global,private
        this.Add = function(objCar) {
            alert('Add');
        }
        this.Get = function(carid) {
            alert('Get');
        }
    }
//static class (2:json)

    var Car = {
        color: 'red',
        doors: 4,
        showColor: function() { alert(this.color); }
    }
    Car.showColor();
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/avon520/archive/2009/01/17/3819751.aspx

转载于:https://blog.51cto.com/fluagen/303152

JavaScript定义类的几种方式相关推荐

  1. JavaScript定义函数的几种方式

    上节我们介绍了<JavaScript工作体系中不可或缺的函数>,函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块.接下来我们说说js当中定义(声明)函数的几种方式,以及每种方式的 ...

  2. JavaScript定义函数的几种方式 1

    上节我们介绍了<JavaScript工作体系中不可或缺的函数>,函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块.接下来我们说说js当中定义(声明)函数的几种方式,以及每种方式的 ...

  3. javascript定义数组的两种方式,获取各个元素的值

    <script type="text/javascript">             //创建数组并赋值             //1声明数组,分配空间,赋值    ...

  4. Javascript定义类(class)的三种方法

    将近20年前,Javascript诞生的时候,只是一种简单的网页脚本语言.如果你忘了填写用户名,它就跳出一个警告. 如今,它变得几乎无所不能,从前端到后端,有着各种匪夷所思的用途.程序员用它完成越来越 ...

  5. JavaScript事件处理程序的3种方式

    最近这段时间因为每天要修改网站,为网站做特效,所以看了很多的js接触事件,自己只会使用一小部分,有时用的时候也比较混乱,现在系统的整理了一下,首先跟大家在马海祥博客上跟大家分享的是JavaScript ...

  6. Java 创建类的四种方式

    Java 创建类的四种方式 对于上学期已经学习过c++的同学,是不是对另一大编程语言产生了浓厚的兴趣,对于c++的面向对象编程,又和java的面向变量有何区别,下面我们从java四种创建对象来说起. ...

  7. @Import注解:导入配置类的四种方式源码解析

    微信搜索:码农StayUp 主页地址:https://gozhuyinglong.github.io 源码分享:https://github.com/gozhuyinglong/blog-demos ...

  8. 代码示例:Java中定义数组的三种方式

    在Java中,数组的定义有三种方式,其基本语法格式如下: 数组类型[] 数组名 = new 数组类型[数组长度]; 数组类型[] 数组名 = new 数组类型[]{数组元素0,数组元素1,...}; ...

  9. javascript 定义类(转载)

    Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的extend或冒号,它也没有用来支持虚函数的virtual,不过,Javascript是一门 ...

最新文章

  1. Javascript 常用技巧55例
  2. PHP内核之PHP_FUNCTION宏定义
  3. 2038: [2009国家集训队]小Z的袜子(hose)+莫队入门
  4. python 生成pdf收据_python如何与以太坊交互并将区块链信息写入SQLite
  5. “数据中台”是什么?
  6. axios (get post请求、头部参数添加)傻瓜式入门axios
  7. vscode创建代码截图_如何在VSCode中创建代码配置文件
  8. 如何在SQL Server中创建视图
  9. Android NFC技术解析,附Demo源码
  10. php_redis配置安装php_redis-5.1.1-7.4-nts-vc15-x64.zip
  11. anylogic和java,基于Anylogic的Java代码入门教程
  12. 张小龙《微信背后的产品观》
  13. UE4 Ultra Dynamic Sky 参数翻译及功能概述
  14. Ghost参数使用详解
  15. xp计算机管理命令,XP系统运行命令在哪打开
  16. 白光模块?彩光模块?
  17. AI创作教程之如何使用简单的 Web API 和 GPU 支持在 Docker 中运行 Stable Diffusion,在 45 秒内启动用于 Stable Diffusion的 Web API
  18. ae教程 (三)三维空间合成(二)
  19. MBR和EFI启动过程
  20. TI AWR1843毫米波雷达采集三维点云数据(ROS)

热门文章

  1. 栈 php 验证格式,表单验证 - 《Biny - 高性能轻量级PHP框架》 - 书栈网 · BookStack...
  2. linux 定时执行搅拌,Linux上定时shell脚本
  3. SSM 整合 3:一个 Spring 入门程序带你来了解什么是控制反转(IoC)/依赖注入(DI)!
  4. java socket编程客户端_Java Socket编程 - 基于Socket实现HTTP下载客户端
  5. 造完家怎么拆东西_吸顶灯灯管怎么拆?吸顶灯拆灯管的注意事项有哪些?
  6. airodump-ng wlan0mon扫描不到网络_MySQL ProxySql 由于漏洞扫描导致的 PROXYSQL CPU 超高...
  7. tiny4412移植tslib库
  8. html5做一个展示页面,基于HTML5的WebGL实现json和echarts图表展现在同一个界面
  9. mysql 有外键 怎么插入数据_外键约束的表怎么插入数据
  10. linux svn 备份脚本,SVN热备份脚本