玩转JavaScript OOP - 类的实现详解


Posted in Javascript onJune 08, 2016

概述

当我们在谈论面向对象编程时,我们在谈论什么?

我们首先谈论的是一些概念:对象、类、封装、继承、多态。

对象和类是面向对象的基础,封装、继承和多态是面向对象编程的三大特性。

JavaScript提供了对象却缺乏类,它不能像C#一样能显式地定义一个类。

但是JavaScript的函数功能非常灵活,其中之一就是构造函数,结合构造函数和原型对象可以实现”类”。

对象和类的概念

对象

“对象”是面向对象编程中非常重要的一个概念,一个对象是一个“东西”(某个人或某件事)的描述。

人和事都来源于现实生活,我们对现实世界的认知就是对人和事的认知。

在编程的领域,代码对于常人来说是抽象的,代码构成的应用是为了更好地解决现实世界的问题。

在分析和设计阶段,使用“对象”的概念能够更好地反应现实世界的问题。

反过来说,代码是包含一些逻辑的,这些逻辑用于描述业务,业务是包含一些业务知识的,业务知识是通过对现实世界的理解和分析总结出来的,这些问题是由现实世界的“对象”构成的。

对象包含特征和行为,用OOP的术语来说,特征是对象的属性,行为是对象的方法。

在现实世界中,相似的对象可以按照一定的标准来分组。例如“蜂鸟”和“老鹰”都被划分到鸟类,鸟类不是一个具体的对象,它是人们根据“蜂鸟”、“老鹰”等那些具体的鸟分析出相似的特征和行为后,归纳出来的一个概念。类相当于一个模板,我们可以基于这个模板创建不同的具体的对象。

在C#中,我们可以定义一个鸟类。

/// <summary>
/// 鸟类
/// </summary>
public class Bird
{
  public void Fly()
  {
    Console.WriteLine("I can fly!");
  }
}

虽然JavaScript是一门面向对象编程语言,但它没有提供class的语法支持。

在JavaScript中,一切都是基于对象的,即使后面要讲的“原型”也都是对象,JavaScript的继承和重用也都是通过原型来实现的。

但是结合构造函数和原型对象可以实现JavaScript的“类”。

构造函数

之前我们使用new Array()创建一个数组,使用new Object()创建一个对象,Array()和Object()是JavaScript内置的两个构造函数,尽管JavaScript没有提供类,但我们可以将Array和Object理解为“类”的概念。

需要注意的是,JavaScript的“类”是由构造函数实现的。

定义构造函数

构造函数也是函数,定义构造函数和其他函数并没有语法上的区别。

唯一的区别是构造函数的首字母应该大写,这也是JavaScript的编程规范。

以下定义了一个Person()构造函数,我们可以将它理解为Person类。

function Person(){
	console.log('I am keepfool.');
}

JavaScript的“类”和构造函数是同时被定义的,在JavaScript中定义“类”时,就同时定义了构造器。

使用构造函数

JavaScript使用类的方式和C#一样,new关键字后面跟着构造函数。

var p = new Person();

玩转JavaScript OOP - 类的实现详解

定义属性和方法

现在我们已经定义好了Person类,可以为Person类添加一些属性和方法。

定义属性

在讲JavaScript对象时,我们讲了对象的属性设置和访问。
这段代码展示了定义对象属性的两种方式:

var cat = {
	color: 'black'
};
cat.name = 'Tom';
console.log(cat.color);
console.log(cat.name);

使用this定义属性

JavaScript类的属性定义方式则有些不同,在构造函数中使用this关键字定义属性:

function Person(name){
	this.name = name;
}

•第一行代码,定义了Person类,并定义了构造函数。

•第二行代码,定义了name属性。

创建并使用对象

以下2行代码创建了两个Person类的对象

var p1 = new Person('James');
var p2 = new Person('Cury');

在Chrome控制台中输出p1.name和p2.name

玩转JavaScript OOP - 类的实现详解

p1和p2是两个不同的对象,修改p1.name不会影响p2.name。

p1.name = 'Lebron James';

玩转JavaScript OOP - 类的实现详解

定义方法

首先,我们区分一下术语“函数”和“方法”,“函数”是独立的单元,而“方法”是依赖于类这个主体存在的。

使用this定义方法

在JavaScript中,类的方法是定义在构造函数中的函数,在构造函数中使用this关键字定义方法:

 

function Person(name) {
	// 定义属性
	this.name = name;
	// 定义方法
	this.sayHello = function() {
		return 'Hello, I am ' + this.name;
	}
}

使用方法

在Chrome控制台分别调用p1和p2对象的sayHello()方法

玩转JavaScript OOP - 类的实现详解

constructor属性

当创建一个对象时,一个特殊的属性被JavaScript自动地分配给对象了,这个属性就是constructor属性。
在chrome控制台输入p1.constructor,可以看到p1对象的constructor属性指向一个函数。

玩转JavaScript OOP - 类的实现详解

瞧瞧这个函数的内容,这不正是Person()构造函数吗?

玩转JavaScript OOP - 类的实现详解

这表示我们也可以通过p1.constructor属性创建对象,

var p3 = new p1.constructor('Steve Nash');

这行代码阐述了一句话:“我不关心p1对象是怎么创建的,但我想让另一个对象如p1一样创建!”

玩转JavaScript OOP - 类的实现详解

在Chrome控制台使用instanceof操作符,可以看到p1、p2、p3都是Person类的实例

玩转JavaScript OOP - 类的实现详解

另外,当我们以{}方式创建对象时,实际上也调用了Object()构造函数。

var o = {};

这行代码声明了一个对象,尽管我们没有设置任何属性和方法,但JavaScript引擎默认给它设置了constructor属性。
o.constructor指向的是Object()构造函数,[native code]显示了Object()是JavaScript内置的函数。

玩转JavaScript OOP - 类的实现详解

原型对象

在JavaScript中,定义一个函数时,函数就会拥有prototype属性,构造函数也不例外。
下图说明了Person()构造函数的prototype属性是一个对象,它是属于函数的,我们称这个属性为原型对象。
从Person类的角度出发,我们也可理解为prototype属性是属于Person类的。

玩转JavaScript OOP - 类的实现详解

同时Person类的实例是没有prototype属性的,上图的p1.prototype是undefined,这说明prototype属性是共享的,这有点像C#中的静态属性。

设置prototype

既然prototype是一个对象,那就可以为它添加属性和方法。

在函数的protpotype属性上定义属性和方法,与设置普通对象的属性和方法没什么区别。
下面的代码为Person.prototype定义了属性和方法。

 

function Person(name){
	this.name = name;
	this.sayHello = function() {
		return 'Hello, I am ' + this.name;
	}
}

// 在构造函数的prototype对象上定义属性和方法
Person.prototype.height = 176;
Person.prototype.run = function(){
	return 'I am ' + this.name + ', I am running!';
}

var p1 = new Person('James');

 使用prototype

在Person.prototype中定义的属性和方法,可以直接被Person类的实例使用,仍然是以object.property的方式使用。

玩转JavaScript OOP - 类的实现详解

需要特别注意的是,namesayHello()是属于Person类的实例,而heightrun()是不属于Person类的实例。

玩转JavaScript OOP - 类的实现详解

小技巧:通过hasOwnProperty方法可以查看对象是否包含某个属性或方法。

自有属性 vs. prototype的属性

Person类的实例既可以使用Person类中的属性,又可以使用Person.prototype中的属性。
那么Person类的属性和Person.prototype的属性有什么差别呢?

首先,我们可以将Person类中的属性和方法理解为“实例属性”。
由于prototype是共享的,我们可以将prototype中的属性和方法理解为“共享属性”。

“实例属性”和“共享属性”的差别主要体现在性能上。
每创建一个Person的实例,就会产生一个name属性和sayHello()方法的副本,而height属性和run()方法则是所有实例共享一个副本。

既然如此,这意味着sayHello()方法可以提到prototype中。
另外,不同的Person实例height可能会不一样,应将它放到Person类中更合理。

 

function Person(name,height){
	this.name = name;
	this.height = height;
}

Person.prototype.sayHello = function(){
	return 'Hello, I am ' + this.name + ', my height is ' + this.height + 'cm.';
}
Person.prototype.run = function(){
	return 'I am ' + this.name + ', I am running!';
}

var p1 = new Person('James',203);
var p2 = new Person('Cury',190);

 

玩转JavaScript OOP - 类的实现详解

类的实现总结

 JavaScript没有类,但构造函数可以实现“类”。

按照JavaScript编程规范,构造函数的首字母应该大写。

“类”的属性和方法是用this.property方式定义在构造函数中的。

在对象创建时JavaScript分配了constructor属性给对象,constructor属性是对象构造函数的一个引用。

函数在定义时就已经有了prototype属性,prototype属性也是一个对象。

prototype是共享的,定义在prototype上的属性和方法可以被“类”的实例使用。

如果属性或方法能够定义在prototype上,就不要定义在构造函数上,使用prototype可以减少内存开销。

以上这篇玩转JavaScript OOP - 类的实现详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery基础知识filter()和find()实例说明
Jul 06 Javascript
JavaScript中的私有/静态属性介绍
Jul 26 Javascript
JS鼠标滑过图片时切换图片实现思路
Sep 12 Javascript
jqgrid 编辑添加功能详细解析
Nov 08 Javascript
js判断浏览器版本以及浏览器内核的方法
Jan 20 Javascript
简单谈谈javascript代码复用模式
Jan 28 Javascript
AngularJS中的Directive实现延迟加载
Jan 25 Javascript
JS实现列表的响应式排版(推荐)
Sep 01 Javascript
vue项目中做编辑功能传递数据时遇到问题的解决方法
Dec 19 Javascript
AngularJS中使用three.js的实例详解
Jul 21 Javascript
在vue项目中引用Iview的方法
Sep 14 Javascript
React优化子组件render的使用
May 12 Javascript
Javascript之String对象详解
Jun 08 #Javascript
浅谈JavaScript函数的四种存在形态
Jun 08 #Javascript
jQuery Ajax和getJSON获取后台普通json数据和层级json数据用法分析
Jun 08 #Javascript
关于session和cookie的简单理解
Jun 08 #Javascript
jQuery封装的屏幕居中提示信息代码
Jun 08 #Javascript
Ext JS框架程序中阻止键盘触发回退或者刷新页面的代码分享
Jun 07 #Javascript
JavaScript基础语法之js表达式
Jun 07 #Javascript
You might like
mac下安装nginx和php
2013/11/04 PHP
php如何获取文件的扩展名
2015/10/28 PHP
thinkPHP通用控制器实现方法示例
2017/11/23 PHP
jquery学习笔记二 实现可编辑的表格
2010/04/09 Javascript
JavaScript 获取当前时间戳的代码
2010/08/05 Javascript
JavaScript的document对象和window对象详解
2010/12/30 Javascript
js制作的鼠标悬浮时产生的下拉框效果
2012/10/27 Javascript
JS模拟自动点击的简单实例
2013/08/08 Javascript
JQuery中绑定事件(bind())和移除事件(unbind())
2015/02/27 Javascript
jQuery toggle 代替方法
2016/03/22 Javascript
分享JS代码实现鼠标放在输入框上输入框和图片同时更换样式
2016/09/01 Javascript
使用jquery给指定的table动态添加一行、删除一行
2016/10/13 Javascript
微信 java 实现js-sdk 图片上传下载完整流程
2016/10/21 Javascript
微信小程序手机号码验证功能的实例代码
2018/08/28 Javascript
web页面和微信小程序页面实现瀑布流效果
2018/09/26 Javascript
Layui Table js 模拟选中checkbox的例子
2019/09/03 Javascript
layui 表格操作列按钮动态显示的实现方法
2019/09/06 Javascript
[02:56]DOTA2英雄基础教程 巨魔战将
2013/12/10 DOTA
在Django中编写模版节点及注册标签的方法
2015/07/20 Python
使用Django的模版来配合字符串翻译工作
2015/07/27 Python
Python实现可自定义大小的截屏功能
2018/01/20 Python
pyQt5实时刷新界面的示例
2019/06/25 Python
PyQt5基本控件使用详解:单选按钮、复选框、下拉框
2019/08/05 Python
利用Tensorboard绘制网络识别准确率和loss曲线实例
2020/02/15 Python
解决pytorch-yolov3 train 报错的问题
2020/02/18 Python
Python中免验证跳转到内容页的实例代码
2020/10/23 Python
浅谈CSS3鼠标移入图片动态提示效果(transform)
2017/11/06 HTML / CSS
英国简约舒适女装品牌:Great Plains
2018/07/27 全球购物
Annoushka英国官网:英国奢侈珠宝品牌
2018/10/20 全球购物
世界上第一个水枕头:Mediflow
2018/12/06 全球购物
制药工程专业毕业生推荐信
2013/12/24 职场文书
党员志愿者活动总结
2014/06/26 职场文书
党员创先争优心得体会
2014/09/11 职场文书
2014年后勤工作总结
2014/11/18 职场文书
2016年社区党支部公开承诺书
2016/03/25 职场文书
2019新学期家长会工作计划
2019/08/21 职场文书