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 继承详解(四)
Jul 13 Javascript
javascript浏览器兼容教程之事件处理
Jun 09 Javascript
bootstrap布局中input输入框右侧图标点击功能
May 16 Javascript
把json格式的字符串转换成javascript对象或数组的方法总结
Nov 03 Javascript
简单实现Bootstrap标签页
Aug 09 Javascript
angular.js中解决跨域问题的三种方式
Jul 12 Javascript
vue-router实现tab标签页(单页面)详解
Oct 17 Javascript
解决layui的input独占一行的问题
Sep 10 Javascript
VScode格式化ESlint方法(最全最好用方法)
Sep 10 Javascript
JS实现吸顶特效
Jan 08 Javascript
ES6扩展运算符和rest运算符用法实例分析
May 23 Javascript
Vue 如何使用props、emit实现自定义双向绑定的实现
Jun 05 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
frename PHP 灵活文件命名函数 frename
2009/09/09 PHP
PHP中的session永不过期的解决思路及实现方法分享
2011/04/20 PHP
php获取数组中重复数据的两种方法
2013/06/28 PHP
PHP常见数组函数用法小结
2016/03/21 PHP
PHP处理数组和XML之间的互相转换
2016/06/02 PHP
Laravel5.1 框架响应基本用法实例分析
2020/01/04 PHP
iframe 自适应高度[在IE6 IE7 FF下测试通过]
2009/04/13 Javascript
jQuery把表单元素变为json对象
2013/11/06 Javascript
jQuery如何实现点击页面获得当前点击元素的id或其他信息
2014/01/09 Javascript
javascript自动给文本url地址增加链接的方法分享
2014/01/20 Javascript
我的NodeJs学习小结(一)
2014/07/06 NodeJs
js简单实现Select互换数据的方法
2015/08/17 Javascript
confirm确认对话框的实现方法总结
2016/06/17 Javascript
Angularjs通过指令监听ng-repeat渲染完成后执行脚本的方法
2016/12/31 Javascript
jquery实现下拉菜单的手风琴效果
2017/07/23 jQuery
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
Node+OCR实现图像文字识别功能
2018/11/26 Javascript
jquery 键盘事件 keypress() keydown() keyup()用法总结
2019/10/23 jQuery
vuejs中父子组件之间通信方法实例详解
2020/01/17 Javascript
React实现类似淘宝tab居中切换效果的示例代码
2020/06/02 Javascript
[37:50]VP vs TNC Supermajor小组赛B组 BO3 第一场 6.2
2018/06/03 DOTA
Python脚本实现集群检测和管理功能
2015/03/06 Python
Python获取当前路径实现代码
2017/05/08 Python
Python字符串格式化%s%d%f详解
2018/02/02 Python
Pandas之Dropna滤除缺失数据的实现方法
2019/06/25 Python
python pymysql链接数据库查询结果转为Dataframe实例
2020/06/05 Python
解决TensorFlow调用Keras库函数存在的问题
2020/07/06 Python
Python读取多列数据以及用matplotlib制作图表方法实例
2020/09/23 Python
html5与css3小应用
2013/04/03 HTML / CSS
Rowdy Gentleman服装和配饰:美好时光
2019/09/24 全球购物
几个MySql的面试题
2013/04/22 面试题
写自荐信要注意什么
2013/12/26 职场文书
伊琍体标语
2014/06/25 职场文书
干部个人对照检查材料
2014/08/25 职场文书
机关领导干部作风整顿整改措施
2014/09/19 职场文书
装修公司管理制度
2015/08/05 职场文书