JavaScript中的类(Class)详细介绍


Posted in Javascript onDecember 30, 2014

在JavaScript中,可以使用类(Class)来实现面向对象编程(Object Oriented Programming)。不过,JavaScript中的类与Java中的有所不同,其相应的定义和使用也不一样。

JavaScript中类的定义

在JavaScript中,所有从同一个原型对象(prototype)处衍生出来的对象组成了一个类;也就是说,JavaScript中的类是一个对象集合的概念,如果两个对象它们的prototype相同,那么它们就属于同一个类;JavaScript中的类甚至都不需要类名。以下面的代码为例:

var p = {x:42};

var a = Object.create(p);

var b = Object.create(p);

console.log(a === b);//false

console.log(Object.getPrototypeOf(a) === Object.getPrototypeOf(b));//true

在上述例子中,对象a和b拥有相同的原型对象(prototype) p,因此a和b属于同一个类(虽然这个类都没有类名),它们从原型对象p处继承了值为42的属性x。

从这个例子中可以看到,原型对象的作用就相当于模板,可以由之衍生/创建出多个对象,其地位与Java语言中的类代码(Class code)相同,是JavaScript中类定义的核心。以下这个例子中的原型对象就呈现出更像类代码的样子:

var p = {

 INCREMENT_BY : 1,

 increment : function(x){

  return x + this.INCREMENT_BY;

 }

}

var a = Object.create(p);

var b = Object.create(p);

console.log(a.increment(7));//8

console.log(b.increment(9));//10

上述例子中,原型对象p定义了一个值为1的property (INCREMENT_BY)和一个名为increment的函数;对象a和b从p这个模板处获取了INCREMENT_BY和increment函数。当调用对象a或b的increment函数时,JavaScript会试图获取a或b的INCREMENT_BY值(this.INCREMENT_BY);由于INCREMENT_BY是从p中获取的,因此其值都是1 — 从模板中获取的,值都相同的变量,类似于Java中的静态类变量(static variable),因此上面的例子中对INCREMENT_BY变量命名时使用了全大写字符。

在上面的例子中,所有从模板p处创建出来的对象(属于同一个类的这些对象),其属性和行为都是一模一样的。但实际上对于同一个类的不同对象,它们除了拥有类所定义的属性/行为以外,往往具有一些自身所特有的属性与行为。因此,如果需要将prototype这个模板当作类来使用的话,就必须对每一个从中衍生出来的对象进行一定的定制:

var p = {

 INCREMENT_BY : 1,

 increment : function(x){

  return x + this.INCREMENT_BY + this.custom_increment_by;

 }

}

var a = Object.create(p);

var b = Object.create(p);

a.custom_increment_by = 0;

b.custom_increment_by = 1;

console.log(a.increment(7));//8

console.log(b.increment(9));//11

在这个例子中,从模板p处创建出来的对象a和b拥有一个彼此间值不一定相等的变量custom_increment_by,而它们的increment()函数这个行为的最终结果则与custom_increment_by的值相关。一般来说,对新建对象进行定制化的工作往往放在统一的函数中进行:

var p = {

 INCREMENT_BY : 1,

 increment : function(x){

  return x + this.INCREMENT_BY + this.custom_increment_by;

 }

}

function getIncrementalClassObject(customIncrementByValue){

 var incrementalObj = Object.create(p);

 incrementalObj.custom_increment_by = customIncrementByValue;

 return incrementalObj;

}

var a = getIncrementalClassObject(0);

var b = getIncrementalClassObject(1);

console.log(a.increment(7));//8

console.log(b.increment(9));//11

如此,便通过原型对象p和getIncrementalClassObject()函数完成了一个类的定义:可以通过调用getIncrementalClassObject()函数来获取原型对象都是p的对象,而在调用getIncrementalClassObject()函数过程中可以对这些新建对象进行一定的定制化。值得注意的是,此时这个已经定义了的类还没有类名,为了方便描述,姑且称之为Incremental。

回顾getIncrementalClassObject()函数中所做的工作,可以看到从Incremental这个类中创建新的对象所经历的过程如下:

1.创建一个空对象,并将其原型对象定义为p。
2.根据不同的参数值,对这个新建的空对象进行定制。
3.返回已经定制完成的新对象。

在JavaScript中,可以通过使用Constructor(构造函数)来快速地完成类的定义以及新对象的创建。

JavaScript中的Constructor(构造函数)

从上述Incremental类这个例子中可以看到,定义新的类需要两部分代码:创建原型对象作为模板、创建自定义函数对新对象进行初始化;而从类中创建新的对象则经历了三个过程:指定新对象的原型对象、定制/初始化新对象、返回这个新对象。在JavaScript中,这一切都可以通过Constructor(构造函数)来完成。

JavaScript中的Constructor是一个函数(function),承担对新对象进行初始化的职责;而这个Constructor函数的prototype则作为模板用于创建新对象。仍以上述Incremental类为例,用Constructor来重写代码后是这样的:

function Incremental(customIncrementByValue){

  this.custom_increment_by = customIncrementByValue;

}

Incremental.prototype = {

  INCREMENT_BY : 1,

 increment : function(x){

  return x + this.INCREMENT_BY + this.custom_increment_by;

 }

}
var a = new Incremental(0);

var b = new Incremental(1);

console.log(a.increment(7));//8

console.log(b.increment(9));//11

通过new关键词,使用Constructor函数来创建新对象这一过程,其实际上经历了以下几个阶段:

创建一个新的空对象。

1.将这个对象的原型对象指向constructor函数的prototype属性。
2.将这个对象作为this参数,执行constructor函数。
3.这与之前的getIncrementalClassObject()函数中所做的工作是一样的。

类名

在使用Constructor创建对象时,相应的对象也就有了“类名”,这可以从instanceof操作符的结果上得到验证:

console.log(a instanceof Incremental);//true

console.log(b instanceof Incremental);//true

不过,instanceof操作符并不判断对象是否由Incremental这一构造函数所创建,instanceof操作符只判断对象的原型对象是否为Incremental.prototype。当存在两个prototype一样的构造函数时,instanceof操作符将统一返回true,而不会区分用于创建对象的构造函数到底是哪个。
function Incremental2(customIncrementByValue){

  this.custom_increment_by = customIncrementByValue + 3;

}

Incremental2.prototype = Incremental.prototype;

console.log(a instanceof Incremental2);//true
Javascript 相关文章推荐
深入浅析JavaScript中对事件的三种监听方式
Sep 29 Javascript
node.js微信公众平台开发教程
Mar 04 Javascript
js获取元素的外链样式的简单实现方法
Jun 06 Javascript
JS实现输入框提示文字点击时消失效果
Jul 19 Javascript
Javascript中的对象和原型(二)
Aug 12 Javascript
AngularJS打开页面隐藏显示表达式用法示例
Dec 25 Javascript
JS排序之冒泡排序详解
Apr 08 Javascript
vue实现图片滚动的示例代码(类似走马灯效果)
Mar 03 Javascript
Node4-5静态资源服务器实战以及优化压缩文件实例内容
Aug 29 Javascript
vue中@change兼容问题详解
Oct 25 Javascript
js实现随机抽奖
Mar 19 Javascript
uin-app+mockjs实现本地数据模拟
Aug 26 Javascript
JavaScript实现防止网页被嵌入Frame框架的代码分享
Dec 29 #Javascript
jQuery实现ichat在线客服插件
Dec 29 #Javascript
jQuery中用dom操作替代正则表达式
Dec 29 #Javascript
jQuery中:animated选择器用法实例
Dec 29 #Javascript
纯JavaScript实现获取onclick、onchange等事件的值
Dec 29 #Javascript
JavaScript实现列出数组中最长的连续数
Dec 29 #Javascript
jQuery中document与window以及load与ready 区别详解
Dec 29 #Javascript
You might like
如何判断php数组的维度
2013/06/10 PHP
功能强大的php分页函数
2016/07/20 PHP
php读取本地json文件的实例
2018/03/07 PHP
Laravel实现短信注册的示例代码
2018/05/29 PHP
javascript 计算两个整数的百分比值
2009/12/26 Javascript
多种方法实现load加载完成后把图片一次性显示出来
2014/02/19 Javascript
Backbone.js 0.9.2 源码注释中文翻译版
2015/06/25 Javascript
javascript实现动态表头及表列的展现方法
2015/07/14 Javascript
用JS动态改变表单form里的action值属性的两种方法
2016/05/25 Javascript
JS实现浏览器打印、打印预览示例
2017/02/28 Javascript
最常用的jQuery表单验证(简单)
2017/05/23 jQuery
react-native ListView下拉刷新上拉加载实现代码
2017/08/03 Javascript
微信小程序实现省市区三级地址选择
2020/06/21 Javascript
Vue中的transition封装组件的实现方法
2019/08/13 Javascript
Vue中跨域及打包部署到nginx跨域设置方法
2019/08/26 Javascript
[02:45]DOTA2英雄敌法师基础教程
2013/11/25 DOTA
python元组操作实例解析
2014/09/23 Python
Python的Flask框架中使用Flask-SQLAlchemy管理数据库的教程
2016/06/14 Python
Python书单 不将就
2017/07/11 Python
python中numpy包使用教程之数组和相关操作详解
2017/07/30 Python
python 输出上个月的月末日期实例
2018/04/11 Python
对Python中列表和数组的赋值,浅拷贝和深拷贝的实例讲解
2018/06/28 Python
django+xadmin+djcelery实现后台管理定时任务
2018/08/14 Python
python3.6使用urllib完成下载的实例
2018/12/19 Python
python读取文件名并改名字的实例
2019/01/07 Python
centos+nginx+uwsgi+Django实现IP+port访问服务器
2019/11/15 Python
Python 基于wxpy库实现微信添加好友功能(简洁)
2019/11/29 Python
如何用H5实现一个触屏版的轮播器的实例
2017/01/09 HTML / CSS
HTML5页面无缝闪开的问题及解决方案
2020/06/11 HTML / CSS
adidas泰国官网:adidas TH
2020/07/11 全球购物
高中运动会入场词
2014/02/14 职场文书
大学生怎样写好自荐信
2014/02/25 职场文书
大学生见习期满自我鉴定
2014/09/13 职场文书
求职简历自我评价怎么写
2015/03/10 职场文书
Golang Elasticsearches 批量修改查询及发送MQ
2022/04/19 Golang
python标准库ElementTree处理xml
2022/05/20 Python