JavaScript 面向对象编程(2) 定义类


Posted in Javascript onMay 18, 2010

本文承接上一篇JavaScript面向对象编程(1) 基础。
上篇说过,JavaScript没有类的概念,需要通过函数来实现类的定义。先通过一个例子说明:

function myClass() 
{ 
var id = 1; 
var name = "johnson"; 
//properties 
this.ID = id; 
this.Name = name; 
//method 
this.showMessage = function() 
{ 
alert("ID: " + this.ID + ", Name: " + this.Name); 
} 
} 
var obj1 = new myClass(); 
var obj2 = new myClass();

function的定义实际上相当于类的构造函数,最后两句是创建这个类的实例。先分析第一句:var obj1 = new myClass(); 当用new创建类的实例时,解释器首先会创建一个空的对象。然后运行这个myClass函数,并将this指针指向这个类的实例。当碰到this.ID = id;和this.Name = name;及this.showMessage = function(){...}时,便会创建这两个属性,和这个方法,并把变量id,name的值一级函数的定义赋给这两个属性及这个函数对象(shwoMessage)。这个过程相当于初始化这个对象,类似于C# 中的构造函数。最后new返回这个对象。再看第二句:var obj2 = new myClass(); 执行过程与上一句代码相同,即创建一个空对象,然后执行myClass这个函数,定义两个属性和一个方法。
从上面的分析中可以看到,上面这种实现类的方式,即在函数的定义中定义类的属性方法。存在着弊端。如果需要创建两个或更多这个类的实例时,上文是两个,这些属性会被重复的创建多次。
那么如何避免这种情况呢?上一篇中也曾提到过用prototype。prototype和它的名字一样是一个原型,每一个function都有一个子对象prototype,它其实表示这个function对象的成员的集合,由于这里我们使用function实现类的,所以可以说prototype其实就是便是类的成员的集合。prototype定义的属性和方法执行在函数的构造体执行之前,所以当new一个对象之前,其实prototype的成员已经执行过了。先看一个例子:
function myClass() 
{ 
//构造函数 
} 
myClass.prototype = 
{ 
ID: 1, 
Name: "johnson", 
showMessage: function() 
{ 
alert("ID: " + this.ID + ", Name: " + this.Name); 
} 
} 
var obj1 = new myClass(); 
var obj2 = new myClass();

类的结构还是和前面的例子相同,只不过这里是利用了prototype来实现。还是先看最后两句,前面说过,prototype是执行在函数构造体之前,即执行到var obj1 = new myClass();之前,这个类已经有了ID,Name属性和showMessage方法。执行者一句时执行过程如下,注意和前一个例子比较:首先还是创建一个空的对象,并把this指针指向这个对象。然后将函数的prototype对象的所有成员都赋给这个对象(注意没有再创建这些成员)。然后执行函数体。最后new返回这个对象。执行下一句时:同样执行此过程,不会重复创建这些成员。
上面的代码还只是一个例子,在实际的项目中,可能出现的是类中有大量的成员,同时可能需要创建大量的实例。这是prototype就会显示其优越性了。另外上面的代码中使用了大括号语法定义了prototype的成员,这样看起来代码更清晰。这是一种比较推荐的类的设计模式。当然在众多的项目中,可能还会发现更好的模式,我们也希望能有更优化的JavaScript的编程模式不断推陈出新,也希望随着时间的推移,各主流浏览器也对JavaScript的解析都标准,统一。
上面说过prototype定义的成员是发生在构造体之前,可以证明一下,在上面的例子中,构造体是空的,在构造函数中加入一句alert(this.Name);,当执行到var obj1 = new myClass();时,会看到弹出对话框,显示正确的属性值。
写了这段文字之后承蒙多为兄弟的点评,收获匪浅。对上面的例子进一步讨论,如下代码:
function subClass(){ } 
subClass.prototype = 
{ 
Name: "sub" 
} 
function myClass() 
{ 
//构造函数 
} 
myClass.prototype = 
{ 
ID: 1, 
Name: "johnson", 
SubObj: new subClass(), 
showMessage: function() 
{ 
alert("ID: " + this.ID + ", Name: " + this.Name + "SubObj.Name:" + this.SubObj.Name); 
} 
} 
var obj1 = new myClass(); 
obj1.SubObj.Name = "XXX"; 
obj1.showMessage(); 
var obj2 = new myClass(); 
obj2.showMessage();

这里在myClass中定义了一个引用类型,其类型是我们自定义的一个subClass类,这个子类中有一个Name属性。由于prototype对象是共享的,按照我们上面的分析:在执行var obj1 = new myClass();时,会把myClass的prototype中的成员复制给这个obj1实例。但这里SubObj是一个引用类型,在执行到var obj2 = new myClass();时,prototype中的ID,Name成员会复制到obj2中,但SubObj这个属性不会复制过去,而是引用了prototype中的SubObj,所以因为上一句修改了obj1.Subobj.Name的值,所以在用new生成obj2实例时,引用到了修改后的值。
所以借用prototype定义类时,依然需要将属性定义在构造体中,而将方法定义在该构造体的原型上。如下:
function myClass(id, name) 
{ 
this.ID = id; 
this.Name = name; 
} 
myClass.prototype = 
{ 
showMessage: function() 
{ 
alert("ID: " + this.ID + ", Name: " + this.Name); 
}, 
showMessage2: function() 
{ 
alert("Method2"); 
} 
} 
var obj1 = new myClass(1, "johnson"); 
obj1.showMessage(); 
obj1.Name="John"; 
obj1.showMessage(); 
var obj2 = new myClass(2, "Amanda"); 
obj2.showMessage();

关于私有成员,共有成员以及静态成员,类的继承,抽象类,虚方法,类的反射等实现方法,以后还会坚持写下去。不过我觉得需要说一下的是,我打算写的是JavaScript面向对象的基础实现,如果需要深入的学习建议参考李战老哥的“甘露模型”。
Javascript 相关文章推荐
基于jquery创建的一个图片、视频缓冲的效果样式插件
Aug 28 Javascript
js中Math之random,round,ceil,floor的用法总结
Dec 26 Javascript
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
Dec 20 Javascript
基于javascript实现精确到毫秒的倒计时限时抢购
Apr 17 Javascript
javascript运算符——位运算符全面介绍
Jul 14 Javascript
详解AngularJs HTTP响应拦截器实现登陆、权限校验
Apr 11 Javascript
解决Vue 浏览器后退无法触发beforeRouteLeave的问题
Dec 24 Javascript
JS计算输出100元钱买100只鸡问题的解决方法
Jan 04 Javascript
vue使用自定义icon图标的方法
May 14 Javascript
JS栈stack类的实现与使用方法示例
Jan 31 Javascript
JavaScript队列结构Queue实现过程解析
Mar 07 Javascript
JavaScript WeakMap使用详解
Feb 05 Javascript
JavaScript 面向对象编程(1) 基础
May 18 #Javascript
Javascript Object.extend
May 18 #Javascript
Jsonp 跨域的原理以及Jquery的解决方案
May 18 #Javascript
javascript 密码强度验证规则、打分、验证(给出前端代码,后端代码可根据强度规则翻译)
May 18 #Javascript
JS request函数 用来获取url参数
May 17 #Javascript
asp.net+js 实现无刷新上传解析csv文件的代码
May 17 #Javascript
JQuery中的ready函数冲突的解决方法
May 17 #Javascript
You might like
全国FM电台频率大全 - 2 天津市
2020/03/11 无线电
PHP面向对象的使用教程 简单数据库连接
2006/11/25 PHP
php中处理mysql_fetch_assoc返回来的数组 不用foreach----echo
2011/05/04 PHP
php学习笔记(三)操作符与控制结构
2011/08/06 PHP
PHP+jQuery实现自动补全功能源码
2013/05/15 PHP
PHP的preg_match匹配字符串长度问题解决方法
2014/05/03 PHP
php中get_object_vars()在数组的实例用法
2021/02/22 PHP
JAVASCRIPT 对象的创建与使用
2021/03/09 Javascript
jquery插件之easing 动态菜单
2010/08/21 Javascript
JS获取当前日期和时间的简单实例
2013/11/19 Javascript
使用jquery+CSS实现控制打印样式
2014/12/31 Javascript
JavaScript函数参数使用带参数名的方式赋值传入的方法
2015/03/19 Javascript
javascript中DOM复选框选择用法实例
2015/05/14 Javascript
jquery显示loading图片直到网页加载完成的方法
2015/06/25 Javascript
详解jQuery UI库中文本输入自动补全功能的用法
2016/04/23 Javascript
谈谈因Vue.js引发关于getter和setter的思考
2016/12/02 Javascript
JavaScript中的函数申明、函数表达式、箭头函数
2019/12/06 Javascript
[02:47]2018年度DOTA2最佳辅助位选手4号位-完美盛典
2018/12/17 DOTA
使用Django启动命令行及执行脚本的方法
2018/05/29 Python
在Python中居然可以定义两个同名通参数的函数
2019/01/31 Python
使用PyQtGraph绘制精美的股票行情K线图的示例代码
2019/03/14 Python
python实现12306登录并保存cookie的方法示例
2019/12/17 Python
pytorch使用 to 进行类型转换方式
2020/01/08 Python
Python原始套接字编程实例解析
2020/01/29 Python
pycharm 2018 激活码及破解补丁激活方式
2020/09/21 Python
使用pygame实现垃圾分类小游戏功能(已获校级二等奖)
2020/07/23 Python
html5 canvas 使用示例
2010/10/22 HTML / CSS
AmazeUI中模态框的实现
2020/08/19 HTML / CSS
预订奥兰多和佛罗里达州公园门票:FloridaTix
2018/01/03 全球购物
Oral-B荷兰:牙医最推荐的品牌
2020/02/25 全球购物
自主实习接收函
2014/01/13 职场文书
单位提档介绍信
2014/01/17 职场文书
2014教育局对照检查材料思想汇报
2014/09/23 职场文书
教师学期末个人总结
2015/02/13 职场文书
如何写辞职书
2015/02/26 职场文书
创业计划书之家教托管
2019/09/25 职场文书