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 相关文章推荐
JS遮罩层效果 兼容ie firefox jQuery遮罩层
Jul 26 Javascript
jquery ajax return没有返回值的解决方法
Oct 20 Javascript
Js-$.extend扩展方法使方法参数更灵活
Jan 15 Javascript
学JavaScript七大注意事项【必看】
May 04 Javascript
jQuery插入节点和移动节点用法示例(insertAfter、insertBefore方法)
Sep 08 Javascript
利用JQuery实现datatables插件的增加和删除行功能
Jan 06 Javascript
Vue中计算属性computed的示例解读
Jul 26 Javascript
react-native DatePicker日期选择组件的实现代码
Sep 12 Javascript
vue 设置路由的登录权限的方法
Jul 03 Javascript
AngularJS中ng-options实现下拉列表的数据绑定方法
Aug 13 Javascript
axios如何利用promise无痛刷新token的实现方法
Aug 27 Javascript
echarts实现晶体球面投影的实例教程
Oct 10 Javascript
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
PHP中的gzcompress、gzdeflate、gzencode函数详解
2014/07/29 PHP
PHP文件与目录操作示例
2016/12/24 PHP
PHP时间处理类操作示例
2018/09/05 PHP
jQuery checkbox全选/取消全选实现代码
2009/11/14 Javascript
JavaScript CSS修改学习第三章 修改样式表
2010/02/19 Javascript
js 遍历json返回的map内容示例代码
2013/10/29 Javascript
jquery 表格排序、实时搜索表格内容(附图)
2014/05/19 Javascript
网页实时显示服务器时间和javscript自运行时钟
2014/06/09 Javascript
JavaScript中操作Mysql数据库实例
2015/04/02 Javascript
JavaScript中几种排序算法的简单实现
2015/07/29 Javascript
jquery ztree实现模糊搜索功能
2016/02/25 Javascript
jquery实现下拉框功能效果【实例代码】
2016/05/06 Javascript
Node.js的基本知识简单汇总
2016/09/19 Javascript
Bootstrap对话框使用实例讲解
2016/09/24 Javascript
input file上传 图片预览功能实例代码
2016/10/25 Javascript
node.js平台下的mysql数据库配置及连接
2017/03/31 Javascript
ES6新特性之变量和字符串用法示例
2017/04/01 Javascript
基于angular6.0实现的一个组件懒加载功能示例
2018/04/12 Javascript
如何基于原生javaScript生成带图片的二维码
2019/11/21 Javascript
原生js实现二级联动菜单
2019/11/27 Javascript
Python实现批量检测HTTP服务的状态
2016/10/27 Python
Python中判断输入是否为数字的实现代码
2018/05/26 Python
解决安装python库时windows error5 报错的问题
2018/10/21 Python
Python参数类型以及常见的坑详解
2019/07/08 Python
CSS3中Transform动画属性用法详解
2016/07/04 HTML / CSS
html5音频_动力节点Java学院整理
2018/08/22 HTML / CSS
BOSE德国官网:尽探索之力,享音乐之极
2016/12/11 全球购物
乡镇干部十八大感言
2014/02/17 职场文书
实习会计求职自荐信范文
2014/03/10 职场文书
建筑技术负责人岗位职责
2015/04/13 职场文书
考生诚信考试承诺书
2015/04/29 职场文书
网聊搭讪开场白
2015/05/28 职场文书
签字仪式主持词
2015/07/03 职场文书
小学毕业感言100字
2015/07/30 职场文书
莫言诺贝尔获奖感言(全文)
2015/07/31 职场文书
Python os和os.path模块详情
2022/04/02 Python