JavaScript之自定义类型


Posted in Javascript onMay 04, 2012

1、直接创建模式。这是最简单也是最直接的一种模式,首先创建一个引用类型的对象,然后为其添加自定义属性和方法。示例代码如下:

var person = new Object(); 
person.name = "Sam"; 
person.age = 16; 
person.speak = function(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
person.speak();

可以看到,上面创建了一个Object类型的对象,然后为其添加了name和age属性以及一个speak方法。直接创建模式虽然简单,但其缺点是显而易见的:当我们需要创建许多相同的对象时,每次都要重复编写代码。为了解决这个问题,我们可以将创建对象的过程进行封装,于是便有了下面的工厂模式。
2、工厂模式。工厂模式是程序设计中一种常用的设计模式,它主要是将创建对象的过程进行了封装,示例代码如下:
function createPerson(name, age){ 
var person = new Object(); 
person.name = name; 
person.age = age; 
person.speak = function(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
return person; 
} 
var person1 = createPerson("Sam", 16); 
var person2 = createPerson("Jack", 18);

使用工厂模式后,创建相同类型的对象变得简单了。但工厂模式没有解决对象识别的问题,即我们无法确定创建的对象的具体类型。有过面向对象编程经验的开发人员都知道,对象的创建应当基于类,有了具体的自定义类,再来创建该类的对象。幸好,在JavaScript中,我们可以通过构造函数模式来模拟一个类。
3、构造函数模式。构造函数和普通函数没有任何区别。任何普通函数都可以作为构造函数,只要使用new操作符即可;任何构造函数也都可以作为普通函数来调用。只不过在JavaScript中,有一个约定,就是用作构造函数的函数名需要首字母大写。示例代码如下:
function Person(name, age){ 
this.name = name; 
this.age = age; 
this.speak = function(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
} 
var person1 = new Person("Sam", 16); 
var person2 = new Person("Jack", 18);

可以看到,在构造函数内部,我们使用了this来添加属性和方法,那么,这个this是指什么呢?当我们创建了一个Person的对象时,this即是指这个创建的对象。现在,我们可以识别出对象person1和person2的具体类型了。使用alert(person1 instanceOf Person)后可以发现,输出的值为true。但构造函数模式也有自己的缺点,就是构造函数内声明的方法在每次创建新对象时都会重新创建(在JavaScript中,函数也是对象)。也就是说,构造函数内的方法是与对象绑定的,而不是与类绑定的。下面代码的输出可以验证我们的推断。
alert(person1.speak == person2.speak); // false 解决这个缺点的一种比较简单的方法就是将函数的声明放到构造函数的外面,即:
function Person(name, age){ 
this.name = name; 
this.age = age; 
this.speak = speak; 
} 
function speak(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
var person1 = new Person("Sam", 16); 
var person2 = new Person("Jack", 18); 
alert(person1.speak == person2.speak); // true

问题解决了,但这种方法又带来了新的问题。首先,函数speak是在全局作用域中声明的,但它却只能被用于Person构造函数,放在全局作用域中有被误用的风险;其次,如果一个自定义类型有很多的方法,则需要声明很多的全局函数,这既将导致全局作用域的污染,也不利于代码的封装。那么,有没有什么办法能让自定义类型的方法成为与类绑定的,又不污染全局作用域呢?答案是使用原型模式。
4、原型模式。在我们声明一个新的函数后,该函数(在JavaScript中,函数也是对象)就会拥有一个prototype的属性。prototype是一个对象,表示会被该函数创建的所有对象拥有的公共属性和方法。示例代码如下:
function Person(){} 
Person.prototype.name="Sam"; 
Person.prototype.age=16; 
Person.prototype.speak = function(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
var person1 = new Person(); 
person1.speak(); 
var person2 = new Person(); 
alert(person1.speak == person2.speak); // true

可以看到,虽然构造函数内没有声明speak方法,但我们创建的对象person1还是能调用speak方法,这是因为JavaScript有一个搜索规则,先搜索实例属性和方法,找到则返回;如果没找到,则再到prototype中去搜索。原型模式使得方法是与类相关的,并且没有污染全局作用域,但其也有自身的缺点:一是所有属性也都与类相关,这意味着所有对象共享一份属性,这显然是不合理的;二是没有办法向构造函数传入初始化数据了。解决的方法很简单,就是混合使用构造函数模式和原型模式。
5、组合模式。示例代码如下:
function Person(name, age){ 
this.name = name; 
this.age = age; 
} 
Person.prototype.speak = function(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
var person1 = new Person(); 
person1.speak(); 
var person2 = new Person(); 
alert(person1.speak == person2.speak); // true

不难发现,组合模式实现了我们的所有需求,这也是目前应用得比较广泛的一种模式。有面向对象编程经验的开发人员可能会觉得将prototype的声明放在构造函数外面有点别扭,那么能否将其放到构造函数里去呢?答案是肯定的,使用动态组合模式即可。
6、动态组合模式。其原理就是先判断原型中的某个属性或方法是不是已经声明过,如果没有声明,则声明整个原型;否则,什么也不用做。示例代码如下:
function Person(name, age){ 
this.name = name; 
this.age = age; 
if (Person.prototype.speak == "undefined"){ 
Person.prototype.speak = function(){ 
alert(this.name + "is " + this.age + "years old"); 
} 
} 
}
Javascript 相关文章推荐
IE之动态添加DOM节点触发window.resize事件
Jul 27 Javascript
javascript简易缓动插件(源码打包)
Feb 16 Javascript
input 输入框获得/失去焦点时隐藏/显示文字(jquery版)
Apr 02 Javascript
javaScript实现浮点数转十六进制字符
Oct 29 Javascript
JavaScript父子窗体间的调用方法
Mar 31 Javascript
使用AmplifyJS组件配合JavaScript进行编程的指南
Jul 28 Javascript
jQuery插件formValidator实现表单验证
May 23 Javascript
详解vue父子模版嵌套案例
Mar 04 Javascript
Vue.directive()的用法和实例详解
Mar 04 Javascript
微信小程序实现圆形进度条动画
Nov 18 Javascript
微信小程序canvas动态时钟
Oct 22 Javascript
jQuery实现动态操作table行
Nov 23 jQuery
Javascript 键盘事件的组合使用实现代码
May 04 #Javascript
仿中关村在线首页弹出式广告插件(jQuery版)
May 03 #Javascript
jQuery 开发者应该注意的9个错误
May 03 #Javascript
jQuery Ajax请求状态管理器打包
May 03 #Javascript
学习从实践开始之jQuery插件开发 菜单插件开发
May 03 #Javascript
Firefox中beforeunload事件的实现缺陷浅析
May 03 #Javascript
统计jQuery中各字符串出现次数的工具
May 03 #Javascript
You might like
印尼林东PWN黄金曼特宁咖啡豆:怎么冲世界上最醇厚的咖啡冲煮教程
2021/03/03 冲泡冲煮
推荐php模板技术[转]
2007/01/04 PHP
php文件操作实例代码
2012/05/10 PHP
PHP URL路由类实例
2013/11/12 PHP
PHP不用递归遍历目录下所有文件的代码
2014/07/04 PHP
浅析PHP中call user func()函数及如何使用call user func调用自定义函数
2015/11/05 PHP
yii实现model添加默认值的方法(2种方法)
2016/01/06 PHP
NodeJS与Mysql的交互示例代码
2013/08/18 NodeJs
js使用eval解析json(js中使用json)
2014/01/17 Javascript
Jquery检验手机号是否符合规则并根据手机号检测结果将提交按钮设为不同状态
2015/11/26 Javascript
jQuery的deferred对象使用详解
2016/09/25 Javascript
bootstrap监听滚动实现头部跟随滚动
2016/11/08 Javascript
通过sails和阿里大于实现短信验证
2017/01/04 Javascript
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
解决微信授权成功后点击按返回键出现空白页和报错的问题
2020/06/08 Javascript
[06:23]2014DOTA2西雅图国际邀请赛 小组赛7月12日TOPPLAY
2014/07/12 DOTA
[01:46]2018完美盛典章节片——坚守
2018/12/17 DOTA
Python中使用Inotify监控文件实例
2015/02/14 Python
Python+Selenium+PIL+Tesseract自动识别验证码进行一键登录
2017/09/20 Python
Python数据结构之顺序表的实现代码示例
2017/11/15 Python
Python下载网络文本数据到本地内存的四种实现方法示例
2018/02/05 Python
Python实现string字符串连接的方法总结【8种方式】
2018/07/06 Python
基于OpenCV python3实现证件照换背景的方法
2019/03/22 Python
详解Python可视化神器Yellowbrick使用
2019/11/11 Python
使用遗传算法求二元函数的最小值
2020/02/11 Python
python新式类和经典类的区别实例分析
2020/03/23 Python
Strawberrynet草莓网新加坡站:护肤、彩妆、香水及美发产品
2018/08/31 全球购物
Brasty罗马尼亚:购买手表、香水、化妆品、珠宝
2020/04/21 全球购物
应届毕业生应聘自荐信范文
2014/02/26 职场文书
领导干部作风整顿个人剖析材料
2014/10/11 职场文书
房地产销售经理岗位职责
2015/02/02 职场文书
2015年组织委员工作总结
2015/04/23 职场文书
html+css合并表格边框的示例代码
2021/03/31 HTML / CSS
教你怎么用Python操作MySql数据库
2021/05/31 Python
利用JavaScript写一个简单计算器
2021/11/27 Javascript
MySQL 外连接语法之 OUTER JOIN
2022/04/09 MySQL