JavaScript之自定义类型

 更新时间:2012年05月04日 00:39:14   作者:  
在JavaScript中,创建一个具有自定义属性和方法的对象有很多种模式,下面一一进行介绍
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");
}
}
}

相关文章

  • 利用D3.js实现最简单的柱状图示例代码

    利用D3.js实现最简单的柱状图示例代码

    D3.js是一个基于数据操作文档JavaScript库。D3帮助你给数据带来活力通过使用HTML、SVG和CSS。D3重视Web标准为你提供现代浏览器的全部功能,而不是给你一个专有的框架。最近在学习D3.js,这个例子是通过d3.js画一个简单的柱状图。下面来一起看看吧。
    2016-12-12
  • JS+HTML5实现获取手机验证码倒计时按钮

    JS+HTML5实现获取手机验证码倒计时按钮

    这篇文章主要介绍了基于JS+HTML5实现获取手机验证码倒计时按钮,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • JavaScript实现的多种鼠标拖放效果

    JavaScript实现的多种鼠标拖放效果

    这篇文章主要介绍了JavaScript实现的多种鼠标拖放效果,涉及JavaScript响应鼠标事件动态变换页面元素属性的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • JS触摸事件、手势事件详解

    JS触摸事件、手势事件详解

    本篇文章主要介绍了JS触摸事件、手势事件详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 前端JavaScript跳转页面的几种方法以及区别详解

    前端JavaScript跳转页面的几种方法以及区别详解

    这篇文章主要介绍了前端JavaScript跳转页面的几种方法以及区别,分别是window.location.href、window.location.assign()、window.location.replace()、window.location.reload()、window.location.hash、window.open()和document.location其中方法,需要的朋友可以参考下
    2025-04-04
  • p5.js实现声音控制警察抓小偷游戏示例解析

    p5.js实现声音控制警察抓小偷游戏示例解析

    这篇文章主要为大家介绍了p5.js实现声音控制警察抓小偷游戏示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Markdown-it将Markdown文本解析转换为HTML

    Markdown-it将Markdown文本解析转换为HTML

    Markdown-it是一款强大的Markdown解析器,支持多种Markdown语法,并能将Markdown文本转换为HTML,通过npm可快速安装,并可在JavaScript项目中简易调用,Markdown-it不仅支持基本Markdown语法,还扩展了表格、脚注等高级功能,同时允许自定义配置和使用插件以增强功能
    2024-10-10
  • 微信小程序使用wx.chooseLocation开发地图怎么做

    微信小程序使用wx.chooseLocation开发地图怎么做

    这篇文章主要介绍了微信小程序使用wx.chooseLocation开发地图流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-12-12
  • 得到当前行的值的javascript代码

    得到当前行的值的javascript代码

    得到当前行的值的javascript代码...
    2007-06-06
  • js使用xml数据载体实现城市省份二级联动效果

    js使用xml数据载体实现城市省份二级联动效果

    这篇文章主要为大家详细介绍了js使用xml数据载体实现城市省份二级联动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11

最新评论