玩转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 相关文章推荐
js获取图片长和宽度的代码
Nov 24 Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
Dec 29 Javascript
JavaScript数组方法总结分析
May 06 Javascript
详解jQuery的Cookie插件
Nov 23 Javascript
零基础轻松学JavaScript闭包
Dec 30 Javascript
JS中LocalStorage与SessionStorage五种循序渐进的使用方法
Jul 12 Javascript
js实现图片放大展示效果
Aug 30 Javascript
JS实现的base64加密解密操作示例
Apr 18 Javascript
详解几十行代码实现一个vue的状态管理
Jan 28 Javascript
详解vue后台系统登录态管理
Apr 02 Javascript
js实现弹窗效果
Aug 09 Javascript
JavaScript中的函数式编程详解
Aug 22 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
微信公众平台网页授权获取用户基本信息中授权回调域名设置的变动
2014/10/21 PHP
封装ThinkPHP的一个文件上传方法实例
2014/10/31 PHP
PHP实现懒加载的方法
2015/03/07 PHP
PHP生成和获取XML格式数据的方法
2016/03/04 PHP
php实现头像上传预览功能
2017/04/27 PHP
PHP判断一个数组是另一个数组子集的方法详解
2017/07/31 PHP
jQueryUI写一个调整分类的拖放效果实现代码
2012/05/10 Javascript
基于jquery的鼠标拖动效果代码
2012/05/30 Javascript
jquery 卷帘效果实现代码(不同方向)
2013/02/05 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
javascript面向对象之this关键词用法分析
2015/01/13 Javascript
Webpack性能优化 DLL 用法详解
2017/08/10 Javascript
浅谈vue的iview列表table render函数设置DOM属性值的方法
2017/09/30 Javascript
js实现ATM机存取款功能
2020/10/27 Javascript
实例分析JS中的相等性判断===、 ==和Object.is()
2019/11/17 Javascript
微信小程序开发(一):服务器获取数据列表渲染操作示例
2020/06/01 Javascript
vue3为什么要用proxy替代defineProperty
2020/10/19 Javascript
[10:14]2018DOTA2国际邀请赛寻真——paiN Gaming不仅为自己而战
2018/08/14 DOTA
Python编码类型转换方法详解
2016/07/01 Python
pandas中Timestamp类用法详解
2017/12/11 Python
Django数据库表反向生成实例解析
2018/02/06 Python
python正则表达式之对号入座篇
2018/07/24 Python
python词云库wordCloud使用方法详解(解决中文乱码)
2020/02/17 Python
django中的数据库迁移的实现
2020/03/16 Python
Python新手学习装饰器
2020/06/04 Python
Debenhams爱尔兰:英国知名的百货公司
2017/01/02 全球购物
亚洲最大的运动鞋寄售店:KicksCrew
2020/11/26 全球购物
电气工程及自动化专业自荐书范文
2013/12/18 职场文书
岗位竞聘书范文
2014/03/31 职场文书
教师节宣传方案
2014/05/23 职场文书
市场营销策划方案
2014/06/11 职场文书
日语专业毕业生自荐书
2014/06/18 职场文书
工作经常出错的检讨书
2014/09/13 职场文书
毕业实习指导教师评语
2014/12/31 职场文书
会计岗位职责范本
2015/04/02 职场文书
运动员代表致辞
2015/07/29 职场文书