JS中类或对象的定义说明


Posted in Javascript onMarch 10, 2014

我们知道,JS是面向对象的。谈到面向对象,就不可避免的要涉及类的概念。一般像c#,java这些强类型语言都有固定的定义类的语法。而JS的不同之处在于它能使用各种方法实现自己的类和对象。一般的实现有以下几种方式:

1.工厂方式
工厂方式是指创建一个返回特定对象类型的工厂函数,示例代码如下:

function createCar(sColor,iDoors,iMpg)
{
   var oTempCar=new Object;
   oTempCar.color=sColor;
   oTempCar.doors=iDoors;
   oTempCar.mpg=iMpg;
   oTempCar.showColor=function()
   {
        alert(this.color); 
   }
   return oTempCar;
}
var oCar1=createCar("red",4,23);
var oCar2=createCar("blue",3,25);
oCar1.showColor();
oCar2.showColor();

这种方式每次调用它的工厂函数,都会创建一个新对象。可问题在于每次生成一个新对象,都要创建新函数showColor,这使得每个对象都有自己的showColor版本,而事实上,所有的对象都共享同一个函数.为解决这个问题,开发者在工厂函数的外面定义了对象的方法,然后赋予对象一个指针指向这个这个函数,如下
function showColor()
{
   alert(this.color);
}
function createCar(sColor,iDoors,iMpg)
{
   var oTempCar=new Object;
   oTempCar.color=sColor;
   oTempCar.doors=iDoors;
   oTempCar.mpg=iMpg;
   oTempCar.showColor=showColor;
   return oTempCar;
}
var oCar1=createCar("red",4,23);
var oCar2=createCar("blue",3,25);
oCar1.showColor();
oCar2.showColor();

这样就不需要为每一个对象都创建自己的showColor函数,而只是创建指向这个函数的指针.这从功能上解决了问题,但是该函数却不像对象的方法。于是,引出了构造函数的方式。

2.构造函数方式
构造函数与工厂函数很相似,示例代码如下:

function Car(sColor,iDoors,iMpg)
{
   this.color=sColor;
   this.doors=iDoors;
   this.mpg=iMpg;
   this.showColor=function()
   {
      alert(this.color);
   }
}
var oCar1=new Car("red",4,23);
var oCar2=new Car("blue",3,25);

在构造函数中,内部无创建对象,而是使用this关键字。使用new运算符调用构造函数时,在执行第一行代码之前先创建一个对象,只有用this才能访问这个对象。但是这会遇到什么问题呢,很显然,它的每个对象也都会创建自己的showColor函数版本。为解决这个问题,引出了以下的原型方式.

3.原型方式
该方式利用了对象的prototype属性,可把它看成创建新对象所依赖的原型。这里,用空构造函数来设置类名。然后把所有的方法和属性都直接赋予prototype属性。如下:

function Car()
{}
Car.prototype.color="red";
Car.prototype.doors=4;
Car.prototype.mpg=23;
Car.prototype.drivers=new Array("Mike","Sue");
Car.prototype.showColor=function()
{
   alert(this.color);
}

原型方式只能直接赋值,而不能通过给构造函数传递参数初始化属性的值。在用这种方式时,会遇到两个问题,不知道大家注意到没有。第一问题是采用这种方式必须创建每个对象后才能改变属性的默认值。而不能在创建每个对象时都会直接有自己所需要的属性值。这点很讨厌。第二个问题在于属性所指的是对象的时候。函数共享不会出现任何问题,但是对象共享却会出现问题。因为每个实例一般都要实现自己的对象。

如下面:

var oCar1=new Car();
var oCar2=new Car();
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//输出 "Mike,Sue,Matt"
alert(oCar2.drivers);//输出"Mike,Sue,Matt"

因此drivers属性只是指向对象的指针,所以所有的实例事实上共享同一个对象。由于出现这这些问题,我们引出了下面的联合使用构造函数和原型方式。

4.混合的构造函数/原型方式
这种方式的思想是用构造函数定义对象的所有非函数属性(包括普通属性和指向对象的属性),用原型方式定义对象的函数属性(方法)。结果使得所有的函数都只被创建一次,而每个对象都有自己的对象属性实例。示例代码如下:

function Car(sColor,iDoors,iMpg)
{
   this.color=sColor;
   this.doors=iDoors;
   this.mpg=iMpg;
   this.drivers=new Array("Mike","Sue");
}
Car.prototype.showColor=function()
{
   alert(this.color);
}
var oCar1=new Car("red",4,23);
var oCar2=new Car("blue",3,25);
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//输出 "Mike,Sue,Matt"
alert(oCar2.drivers);//输出 "Mike,Sue"

由实例代码可知,这种方式同时解决了上一种方式的两个问题。不过,采用这种方式,仍有些开发者觉得不够完美。

5.动态原型方式
我们可知,大多数面向对象语言都对属性和方法进行了视觉上的封装。而上述方式的showColor方法却定义在了类的外面。因此,他们设计了动态原型方法。这种方式的基本思想和混合的构造函数/原型方式相同,唯一不同之处在于对象方法的位置。如下所示:

function Car(sColor,iDoors,iMpg)
{
   this.color=sColor;
   this.doors=iDoors;
   this.mpg=iMpg;
   this.drivers=new Array("Mike","Sue");
   if(typeof Car._initialized=="undefined")
  {
     Car.prototype.showColor=function()
     {
        alert(this.color);
     }
  }
  Car._initialized=true;
}

这种方式Car.prototype.showColor只被创建一次。这样依赖,这段代码更像其他语言中的类定义了。

6.混合工厂方式
这种方式通常是不能应该前一种方式的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。

function createCar()
{
   var oTempCar=new Object;
   oTempCar.color=“red”;
   oTempCar.doors=4;
   oTempCar.mpg=23;
   oTempCar.showColor=function()
   {
        alert(this.color); 
   };
   return oTempCar;
}
var car=new Car();

由于在Car()构造函数内部调用了new运算符,所以自动忽略第二个new运算符。在构造函数内部创建的对象被传递回变量var。这种方式在对象方法的内部管理方面与经典方式有着相同的问题。所以强烈建议:除非万不得已,还是避免使用这种方式。
Javascript 相关文章推荐
JavaScript高级程序设计 事件学习笔记
Sep 10 Javascript
JavaScript生成的动态下雨背景效果实现方法
Feb 25 Javascript
JQuery中serialize() 序列化
Mar 13 Javascript
深入浅析JavaScript中的Function类型
Jul 09 Javascript
AngularJS入门教程之Select(选择框)详解
Jul 27 Javascript
简化vuex的状态管理方案的方法
Jun 02 Javascript
vue填坑之webpack run build 静态资源找不到的解决方法
Sep 03 Javascript
Vue CLI3搭建的项目中路径相关问题的解决
Sep 17 Javascript
vue 中 beforeRouteEnter 死循环的问题
Apr 23 Javascript
node删除、复制文件或文件夹示例代码
Aug 13 Javascript
Vue.use()在new Vue() 之前使用的原因浅析
Aug 26 Javascript
JavaScript复制变量三种方法实例详解
Jan 09 Javascript
Node.js中AES加密和其它语言不一致问题解决办法
Mar 10 #Javascript
JS中的构造函数详细解析
Mar 10 #Javascript
node.js使用nodemailer发送邮件实例
Mar 10 #Javascript
php中给js数组赋值方法
Mar 10 #Javascript
javascript操作referer详细解析
Mar 10 #Javascript
JS数组的赋值介绍
Mar 10 #Javascript
JS删除字符串中重复字符方法
Mar 09 #Javascript
You might like
php xml-rpc远程调用
2008/12/19 PHP
ajax+php打造进度条代码[readyState各状态说明]
2010/04/12 PHP
PHP的几个常用数字判断函数代码
2012/04/24 PHP
在WordPress中获取数据库字段内容和添加主题设置菜单
2016/01/11 PHP
关于php支持的协议与封装协议总结(推荐)
2017/11/17 PHP
PHP编程实现的TCP服务端和客户端功能示例
2018/04/13 PHP
PHP判断是否微信访问的方法示例
2019/03/27 PHP
使用 Node.js 做 Function Test实现方法
2013/10/25 Javascript
vue实现可增删查改的成绩单
2016/10/27 Javascript
Js实现京东无延迟菜单效果实例(demo)
2017/06/02 Javascript
如何通过非数字与字符的方式实现PHP WebShell详解
2017/07/02 Javascript
select获取下拉框的值 下拉框默认选中方法
2018/02/28 Javascript
完美解决axios在ie下的兼容性问题
2018/03/05 Javascript
Vue.set()动态的新增与修改数据,触发视图更新的方法
2018/09/15 Javascript
vue如何解决循环引用组件报错的问题
2018/09/22 Javascript
js实现鼠标点击页面弹出自定义文字效果
2019/12/24 Javascript
使用Taro实现小程序商城的购物车功能模块的实例代码
2020/06/05 Javascript
在vue中使用jsonp进行跨域请求接口操作
2020/10/29 Javascript
[04:55]完美世界副总裁蔡玮:DOTA2的自由、公平与信任
2013/12/18 DOTA
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
Python实现图像几何变换
2015/07/06 Python
Python 专题六 局部变量、全局变量global、导入模块变量
2017/03/20 Python
zookeeper python接口实例详解
2018/01/18 Python
Python 将pdf转成图片的方法
2018/04/23 Python
详解Django中间件执行顺序
2018/07/16 Python
Python如何处理大数据?3个技巧效率提升攻略(推荐)
2019/04/15 Python
python pytest进阶之xunit fixture详解
2019/06/27 Python
python中doctest库实例用法
2020/12/31 Python
美国和加拿大计算机和电子产品购物网站:TigerDirect.com
2019/09/13 全球购物
幼儿园消防演练方案
2014/02/13 职场文书
学雷锋树新风演讲稿
2014/05/10 职场文书
移交协议书
2014/08/19 职场文书
幼儿园安全工作总结2015
2015/04/20 职场文书
读《推着妈妈去旅行》有感1500字
2019/10/15 职场文书
MySQL单表千万级数据处理的思路分享
2021/06/05 MySQL
python保存图片的四个常用方法
2022/02/28 Python