JavaScript OOP(2)定义JavaScript类
5.1.7 定义类的方式(工厂方式、构造函数、原型方式、混合方式)

在面向对象的开发中,类被认为是对象的模板。在JavaScript中,可以由开发者自定义类及类的方法和属性。

首先学习最基本的制造类的方法,工厂方式。工厂方式的特点是通过特定的工厂方法创建特定类型的对象。典型的工厂方式的实现代码如下:

function createStudnetFactory()

{

var stu=new Object();

stu.ID="1";

stu.Name="hong shi dan";

stu.Skill="Ajax & JavaScript & ASp.NET";

stu.Show=function()

{

alert(stu.Skill);

}

return stu;

}

var stu=createStudnetFactory();

stu.Show();

现在来看看工厂方法的效果,如图5.2所示:

图5.2 工厂方法效果图

可以清楚的看到,对话框显示的正是工厂创建的stu对象的Skill属性的值。实际上,工厂方法可以使用参数来设定所创建对象的各项属性值。带参工厂方法如下所示:

function createStudnetFactory(id,name,skill)

{

var stu=new Object();

stu.ID=id;

stu.Name=name;

stu.Skill=skill;

stu.Show=function()

{

alert(stu.Skill);

}

return stu;

}

var stu=createStudnetFactory(1,"hongbo","Ajax");

stu.Show();

var reader=createStudnetFactory(2,"读者","Ajax");

reader.Show();

带参工厂方法的效果,如图5.3所示:

图5.3 带参工厂方法的效果图

可以清楚的看到,对话框显示的正是工厂方法中传入的skill参数的值。

还有一种与传统面向对象语言更相似的创建对象的方法,即构造函数方式。构造函数方式很像工厂方式,但是构造函数方式可以于new关键字联用。构造函数方式示例代码如下:

function StudentConstract(id,name,skill)

{

this.ID=id;

this.Name=name;

this.Skill=skill;

this.ShowSkill=function()

{

window.alert(this.Skill);

}

}

var stu=new StudentConstract(1,"hongbo","Ajax");//构造函数与new关键字联用

stu.ShowSkill();

在上例中,可以看到构造函数和new关键字的联用进行对象实例化。但是构造函数方式和工厂方式都1个不可以忽略的弊端,每个对象被实例化时,都会实例化类中的方法。这个弊端会造成每个对象都有独立的方法版本。

实际上,还有一种方式可以避免这种弊端。在开发中,可以使用原型方式进行对象的创建。可以通过以下代码实现原型方式:

function Student()

{

//这里可以看做是Student的构造函数

}

Student.prototype.Id="1";

Student.prototype.Name="Hongbo";

Student.prototype.Skill="Ajax";

Student.prototype.Likes=new Array("编码","游戏");

Student.prototype.ShowSkill=function()

{

alert(this.Skill);

}

var stu1=new Student();

stu.ShowSkill();

alert(stu.Likes);//注意这个消息框中的信息

在上例的代码中,首先定义了1个无参的构造函数。然后,通过Student类的prototype添加属性和各种方法。当通过构造函数实例化对象时,所有对象中放入的都是指向属性和方法的指针。通过原型方式,实现了类中属性和方法的共享。

但是原型方式真的就完美无缺了吗?首先,原型方式定义的类没有带参构造函数,实例化对象后需要一一对对象的属性赋值。其次,所有的对象中包含的都是对属性的引用,这意味着所有对象的属性都是对象公有的。当更改任何对象的1个属性时,都会影响其他对象的属性。以下的代码展现了原型方式的缺陷:

function Student()

{

//这里可以看做是Student的构造函数

}

Student.prototype.Id="1";

Student.prototype.Name="Hongbo";

Student.prototype.Skill="Ajax";

Student.prototype.Likes=new Array("编码","游戏");

Student.prototype.ShowSkill=function()

{

alert(this.Skill);

}

var stu1=new Student();

var stu2=new Student();

stu2.Likes.push("旅行");

alert(stu1.Likes); <!--注意这个消息框中的信息-->

alert(stu2.Likes); <!--注意这个消息框中的信息-->

上例运行的效果如图5.4所示:

图5.4 原型方式的缺陷

读者一定会被运行上例的代码的结果惊呆了!读者一定看到了两个相同的消息框,而在代码中实际仅仅更改了stu2的Likes属性,实际上stu1的Likes属性也受到了更改。导致这个结果的原因很简单,stu1和stu2实例化时,它们的Likes属性都仅仅是指向1个数组的引用指针,当数组本身发生变化时,所有指向该数组的指针都会得到修改后的数组。

原型方式、构造方式、工厂方式等等方法都有不可弥补的缺陷,到底那种方式可以完美的实现对象的创建呢?现在使用最多的方式是混合方式,混合方式是指联合使用构造函数和原型方式,就可以像其他面向对象语言一样创建对象了。

混合方式是通过构造函数方式定义对象的所有非函数属性,用原型方式定义对象的函数属性。使用混合方式可以规避构造函数方式和原型方式的缺陷。对象实例化时,所有的属性都是单一对象私有的,而方法则是所有对象公有的。使用混合方式,修改上例的代码如下:

function Student(id,name,skill)

{

this.ID=id;

this.Name=name;

this.Skill=skill;

this.Likes=new Array("编码","游戏");

}//构造函数定义对象的非函数属性

Student.prototype.ShowSkill=function()//通过原型方式定义对象的函数

{

alert(this.Skill);

}

var stu1=new Student(1,"Hongbo","Ajax");

var stu2=new Student(2,"Reader","JavaScript");

stu2.Likes.push("旅行");

stu1.ShowSkill();

stu2.ShowSkill();

alert(stu1.Likes);<!--注意这里的消息框-->

alert(stu2.Likes);

运行以上的代码,可以看到stu1、stu2的Likes属性并不一致,它们保持了各自属性的独立。stu1、stu2调用ShowSkill()方法,可以看到消息框中的消息不一致,即方法识别了this指针。ShowSkill()方法实现了所有对象的公有。

读者看到混合方式时,肯定还是伴随着失望。因为混合方式和传统的面向对象语言还是有很大的差别,混合方式并没有对对象的属性和方法进行严密的封装。在JavaScript中,提供了动态原型方式进行对对象的属性和方法进行严密封装。实现动态原型方法代码如下:

function Student(id,name,skill)

{

this.Id=id;

this.Name=name;

this.Skill=skill;

this.Likes=new Array("编码","游戏");

if(typeof(Student._initialized)=="undefined")

{

Student.prototype.ShowSkill=function()

{

alert(this.Skill);

}

Student._initialized=true;

}

}

var stu1=new Student(1,"hongbo","Ajax");

var stu2=new Student(2,"Reader","JavaScript");

stu2.Likes.push("旅行");

stu1.ShowSkill();

stu2.ShowSkill();

alert(stu1.Likes);

alert(stu2.Likes);

在上例中,运行结果与混合方式是一致的。动态原型方式实现了对象间属性的独立和方法的共享。

实际上,动态原型方式和混合方式非常相似。唯一的不同在于动态原型添加了1个if判断,这里肯定让很多读者不解。typeof(Student._initialized)到底是什么?实际上Student._initialized是由开发者自定义的属性,用于判断当前对象是否被实例化了。

在对象初始化完成前,Student._initialized并没有被声明或实例化,所以Student._initialized一定是undefined,那么就一定会执行if中的代码。If中的代码让对象的ShowSkill函数属性成为1个函数的引用,这样就实现了方法被所有对象公有。

学习了如此多的创造类的方式,到底应该使用那种最好呢?请仔细阅读下一节。

5.1.8 实例以及实例方式使用的注意事项

在面向对象的JavaScript开发中,目前使用最广泛的是混合方式。动态原型方式也能够实现面向对象的基本特征,并且越来越流行。在开发中,可以采用这两种方式中的任何一种。尽量不要单独使用工厂方式、构造函数方式、原型方式的任何一种,否则会给开发带来不可预期的问题。

转载于:https://www.cnblogs.com/hongbo830521/archive/2009/04/10/1433221.html

JavaScript OOP(2)定义JavaScript类相关推荐

  1. html中数组的定义,javascript中数组定义的几种方式是什么?

    javascript中怎么定义数组?下面本篇文章给大家介绍一下javascript数组定义的几种方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 1.什么是数组 数组就是一组数据 ...

  2. 在JavaScript函数中定义全局变量

    是否可以在JavaScript函数中定义全局变量? 我想在其他函数中使用trailimage变量(在makeObj函数中声明). <html xmlns="http://www.w3. ...

  3. javascript的函数定义的区别

    javascript中函数定义通常有两种方法: 1. 普通的函数定义: function f1 (){} 2. 变量式函数定义: var f2 = function(){} 还有一种定义方法是new ...

  4. QML中定义JavaScript资源

    QML中定义JavaScript资源 QML中定义JavaScript资源 共享的JavaScript资源(库) QML中定义JavaScript资源 QML应用程序的程序逻辑可以在JavaScrip ...

  5. JavaScript面向对象——理解构造函数继承(类继承)

    JavaScript面向对象--理解构造函数继承(类继承) 构造函数式继承(类继承) function SuperClass(id) {// 引用类型公有属性this.books = ['JavaSc ...

  6. 基于javascript的asp数据库操作类,含分页、字符串截取、用户登陆验证[原创]

    2005.01.15发表于blog.csdn.net/zxub 无聊又用了用asp,发现还是不爽,已经习惯了面向对象了,就想改进了,vbscript不用,感觉看起来很不爽,就用javascript写了 ...

  7. javascript 总结(常用工具类的封装)(转)

    转载地址:http://dzblog.cn/article/5a6f48afad4db304be1e7a5f javascript 总结(常用工具类的封装) JavaScript 1. type 类型 ...

  8. javascript 总结(常用工具类的封装,转)

    javascript 总结(常用工具类的封装) 前言 因为工作中经常用到这些方法,所有便把这些方法进行了总结. JavaScript 1. type 类型判断 isString (o) { //是否字 ...

  9. JavaScript JS 如何定义多行文本

    JavaScript JS 如何定义多行文本 JavaScript JS 定义多行文本最优雅的方式 var lines = function () { 你的文本内容开始 asd ccac文本结束}; ...

最新文章

  1. 基于Kubernetes 的机器学习工作流
  2. c语言动态申请函数,C语言用malloc函数申请二维动态数组
  3. tomcat双击startup.bat启动时闪退
  4. Android .so和.a的makefile
  5. vue使用class添加动态类
  6. 作者:孙忠富(1957-),男,中国农业科学院农业环境与可持续发展研究所研究员。...
  7. 18 Python 模块引入
  8. Ubuntu 14.04/16.04 (使用apt-get进行安装) 安装Docker
  9. 数据结构经典问题——出栈顺序 转载至:canlynet微博
  10. python日记Day12——numpy速查中文手册
  11. Android 热补丁方案
  12. 中考词汇测试软件,百词斩中考版
  13. @mentions for Users with ActionText; 使用Tribute.js库
  14. “互联网寒冬”来袭,软件测试人员该如何度过这次危机?
  15. 强大的可配置业务化后台管理系统
  16. unity Quality Settings 质量设置
  17. linux 设置默认播放设备,Ubuntu MATE 19.10采用GNOME MPV(Celluloid)做为默认媒体播放器...
  18. Hadoop精华问答 | 基于Hadoop的数据中心有什么好处?
  19. 我在印尼工作的日子-工作餐食
  20. 佳能G4810彩色喷墨打印机更换墨盒

热门文章

  1. spark变量使用broadcast、accumulator
  2. LeetCode 12 Integer to Roman (整数转罗马数字)
  3. c++还有一个小时考试
  4. Struts2框架的学习遇到的问题
  5. 思路,如何快速应对客户提出的业务需求
  6. 面试题目之 ----使用非迭代方法快速排序
  7. svn git 导入本地文件到远程服务器 import
  8. Android Launcher3(二) -- Drag拖动实现
  9. python 做山水画_服了!年度最强的编程语言来了!它不是Python!
  10. Android之组件化开发