JavaScript面向对象编程入门教程


Posted in Javascript onApril 16, 2014

尽管面向对象JavaScript与其他语言相比之下存在差异,并由此引发了一些争论,但毋庸置疑,JavaScript具有强大的面向对象编程能力

本文先从介绍面向对象编程开始,然后回顾JavaScript对象模型,最后演示JavaScript中的面向对象编程概念。

JavaScript回顾

如果你对诸如变量(variables)、类型(types)、函数(functions)、以及作用域(scope)等JavaScript概念觉得心里没底,那么你可以阅读重新介绍JavaScript中的这些主题。你还可以查阅JavaScript 1.5核心指南

面向对象编程

面向对象编程是一种编程范式(paradigm),即使用抽象来创建基于真实世界的模型。它使用了几种以前建立的范式技术,包括模块化(modularity)、多态(polymorphism)、和封装(encapsulation)。今天,许多流行的编程语言(比如Java、JavaScript、C#、C++、Python、PHP、Ruby、以及Objective-C)都支持面向对象编程(OOP)。

面向对象编程可视为使用协作对象集合来进行软件设计,这与传统观点相反,传统观点把程序视为函数集合,或者简化为计算机指令列表。在面向对象编程中,每个对象都具有以下能力:接收消息、处理数据、以及给其他对象发送消息。每个对象都可以视为一个独立的具有不同角色或责任的小机器。
面向对象编程旨在为编程提升更大的灵活性和可维护性,并在大规模软件工程中广泛流行。由于其非常重视模块化,因此面向对象代码旨在让开发更简单、稍后理解起来更容易,而且相对于较少采用模块化的编程方法,使得对于复杂情况及步骤的分析、编码和理解更加直接。

专用术语

类(Class)
~ 定义对象的特征(characteristics)。
对象(Object)
~ 类的实例(Instance)。
属性(Property)
~ 某一对象特征(characteristic),例如颜色。
方法(Method)
~ 某种对象能力,例如行走。
构造函数(Constructor)
~ 实例化(instantiation)时所调用的方法。
继承(Inheritance)
~ 一个类可以继承来自另一个类的特征。
封装(Encapsulation)
~ 一个类只定义该对象的特征,一个方法只定义该方法如何执行。
抽象(Abstraction)
~ 将某一对象的复杂继承、方法、属性结合在一起,而且必须能够模拟某一现实模型。
多态(Polymorphism)
~ 不同类可能会定义相同的方法或属性。
对于面向对象编程的进一步描述,参阅维基百科的面向对象编程词条。

基于原型的编程

基于原型的编程(Prototype-based programming)是一种面向对象编程风格,其中类(classes)并不存在,并且行为重用(在基于类的语言中称为继承)是通过粉饰充当原型的现存对象来完成的。这种模式也称为无类的(class-less)、面向原型的(prototype-oriented)、或基于实例(instance-based)的编程。
关于基于原型语言的最初(且非常规范的)示例就是由David Ungar和Randall Smith开发的Self编程语言。然而,这种无类编程风格最近越来越受欢迎,并且已被一些编程语言采用,例如avaScript、Cecil、NewtonScript、Io、MOO、REBOL、Kevo、Squeak(当使用Viewer框架来操纵Morphic组件时)、及其他几种语言。

JavaScript面向对象编程

核心对象(Core Objects)

JavaScript有几个包含在其核心中的对象;例如,Math、Object、Array、以及String等对象。下面的示例演示了如何使用Math对象的random()方法获取随机数。

alert(Math.random());

提示:本例和所有其他示例都假设已在全局范围内定义了函数名alert(正如包含在web浏览器中的alert一样)。alert函数实际上不是JavaScript本身的一部分。

JavaScript核心对象列表,参阅JavaScript 1.5核心参考:全局对象(Global Objects)。

JavaScript中的每个对象都是一个Object对象的实例,并因此继承其所有属性和方法。

自定义对象(Custom Objects)

类(The Class)

JavaScript是基于原型的语言,其中不包含可在如 C++或Java中找到的类声明(class statement)。有时这会让一些习惯于具有类声明语言(languages with a class statement)的程序员感到困惑。不过,JavaScript用函数(functions)作为类。定义一个类简单到就是定义一个函数。在下例中,我们定义了名为Person(人)的新类。

function Person() { }

对象(类实例)(The Object (Class Instance))

要创建obj对象的一个新实例,我们使用语句new obj,同时将结果(其类型是obj)赋给某个变量(variable),以便稍后访问。
在下例中,我们首先定义名为Person的类,然后创建两个实例(person1和person2)。

function Person() {}
var person1 = new Person();
var person2 = new Person();

还可参阅新的实例化替代方法Object.create。

构造函数(The Constructor)

当实例化时(创建对象实例的瞬间)是会调用构造函数。构造函数是类的一个方法。而在JavaScript中,会函数(function)作为作为该对象的构造函数;因此,也就无需显式定义一个构造函数方法。类中声明的每个行为在实例化时都会执行。

构造函数用于设置对象属性或调用方法为使用该对象做准备。本文稍后会介绍,通过使用一种不同的语法来添加类方法及其定义 。

在下例中,当实例化Person时,Person类的构造函数会显示一个警告框。

function Person() {
    alert('Person instantiated');
}
var person1 = new Person();
var person2 = new Person();

属性(对象属性)(The Property (object attribute))

属性是包含在类中的变量;每个对象实例都有这些属性。属性应设置在类(函数)的原型(prototype)属性中,以便继承正常工作。
在类中操作属性是通过this关键字实现的,this引用当前对象。在类外部访问(读或写)某个属性要通过以下语法:InstanceName.Property;这与C++、Java、以及其他一些语言所用语法相同。(在类内部使用this.Property的语法来获取或设置属性值)。

在下例中,我们为Person类定义gender(性别)属性,然后在初始化时定义该属性。

function Person(gender) {
    this.gender = gender;
    alert('Person instantiated');
}
var person1 = new Person('Male'); // Male: 男
var person2 = new Person('Female'); // Female: 女
//显示person1的性别
alert('person1 is a ' + person1.gender); // person1 is a Male

方法(The methods)

方法遵循与属性相同的逻辑;区别在于它们是函数而且被定义为函数。调用方法与访问属性相似,不过你要在方法名末尾添加(),可能会有参数(arguments)。定义一个方法,就是为该类prototype属性上的某个命名属性指定一个函数;函数被分配到的那个名称就是在对象上调用该方法的名称。
在下例中,我们为Person类定义并使用sayHello()方法。

function Person(gender) {
    this.gender = gender;
    alert('Person instantiated');
}
Person.prototype.sayHello = function() {
    alert('hello');
};
var person1 = new Person('Male');
var person2 = new Person('Female'); // 调用Person的sayHello方法。
person1.sayHello(); // hello

在JavaScript中,方法是作为属性被绑定到某个类/对象的普通函数对象,这意味着,可以“脱离上下文(out of the context)”来调用它们。考虑如下示例代码:

function Person(gender) {
    this.gender = gender;
}
Person.prototype.sayGender = function() {
    alert(this.gender);
};
var person1 = new Person('Male');
var genderTeller = person1.sayGender;
person1.sayGender(); // alerts 'Male'
genderTeller(); // alerts undefined
alert(genderTeller === person1.sayGender); // alerts true
alert(genderTeller === Person.prototype.sayGender); // alerts true

此示例一次演示了多个概念。这表明,在JavaScript中没有“基于对象的方法(per-object methods)”,因为该方法的所有引用都指向完全相同的函数,即我们起初在原型上定义的那个函数。当某个函数被作为方法(或确切地说是属性)调用时,JavaScript会将当前的“对象上下文(object context)”“绑定”到特定的“this”变量。这与调用该函数对象的“call”方法等效,如下所示:
genderTeller.call(person1); //alerts 'Male'e

更多相关信息,请参阅Function.call和Function.apply

继承(Inheritance)

继承是一种方法,用于创建作为一个或多个类专用版本的类。(JavaScript仅支持单类继承)。这个专用类通常被称为子类(child),而其他类通常被称为父类(parent)。在JavaScript中,你要完成继承,需将父类的实例赋给子类,然后将子类特化(specializing)。

提示:由于JavaScript不检测的子类的prototype.constructor(原型的构造函数),参阅Core JavaScript 1.5核心参考:Global Objects:Object:prototype属性,因此我们必须手动指定该值。

在下例中,我们定义Student类作为Person的子类。然后我们重新定义sayHello()方法,并添加sayGoodBye()方法。

// 定义Person类
function Person() {}
Person.prototype.walk = function() {
    alert('I am walking!');
};
Person.prototype.sayHello = function() {
    alert('hello');
};
// 定义Student类
function Student() {
    //调用父类构造函数
    Person.call(this);
}
// 继承Person
Student.prototype = new Person(); // 修正构造函数指针,由于它指向Person
Student.prototype.constructor = Student; // 替换sayHello方法
Student.prototype.sayHello = function() {
    alert('hi, I am a student');
}
// 添加sayGoodBye方法
Student.prototype.sayGoodBye = function() {
    alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye(); // 检验继承
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true

封装

在上例中,Student无须知晓Person类的walk()方法是如何实现的,但仍可使用该方法;Student类无须显式定义该方法,除非我们想改变它。这称为封装(encapsulation),这样每个类继承其父类的方法,并且只需定义它所希望改变的东西。

抽象

抽象是一种机制(mechanism),允许对处理中的问题的当前部分进行建模。这可以通过继承(特化)或组合(composition)来实现。JavaScript通过继承实现特化(specialization),通过让类实例成为其他对象的属性值实现组合。
JavaScript的Function类继承自Object类(这说明模型的特化),并且Function.prototype属性是Object的实例(这说明了组合)。

var foo = function() {};
alert('foo is a Function: ' + (foo instanceof Function));
alert('foo.prototype is an Object: ' + (foo.prototype instanceof Object));

多态

就像所有的方法和属性被定义在原型属性内部一样,不同的类可以定义具有相同名称的方法;方法的作用域限于定义它们的类之内。这仅当两个类之间没有父子关系(当一个类没有从继承链中的其他类继承时)时才为真。

提示

本文中所提出的面向对象编程实现技术不仅适用于JavaScript,因为就如何进行面向对象编程而言,这是非常灵活的。
同样,这里展示的技术既没有使用任何语言技巧(language hacks),也没有模仿其他语言的对象理论实现。
在JavaScript中,还有其他更高级的面向对象编程的技术,但是那些内容已超出了这篇介绍性文章的范围。

Javascript 相关文章推荐
cookie.js 加载顺序问题怎么才有效
Jul 31 Javascript
js中的eventType事件及其浏览器支持性介绍
Nov 29 Javascript
js判断浏览器是否支持html5
Aug 17 Javascript
Dojo获取下拉框的文本和值实例代码
May 27 Javascript
微信小程序 textarea 详解及简单使用方法
Dec 05 Javascript
一个炫酷的Bootstrap导航菜单
Dec 28 Javascript
JavaScript实现的原生态兼容IE6可调可控滚动文字功能详解
Sep 19 Javascript
vue+webpack中配置ESLint
Nov 07 Javascript
详解vue中async-await的使用误区
Dec 05 Javascript
Node.js之readline模块的使用详解
Mar 25 Javascript
node中使用log4js4.x版本记录日志的方法
Aug 20 Javascript
jQuery HTML获取内容和属性操作实例分析
May 20 jQuery
jQuery的cookie插件实现保存用户登陆信息
Apr 15 #Javascript
jquery实现点击文字可编辑并修改保存至数据库
Apr 15 #Javascript
jQuery制作的别致导航有阴影背景高亮模式窗口
Apr 15 #Javascript
JS比较2个日期间隔的示例代码
Apr 15 #Javascript
模拟一个类似百度google的模糊搜索下拉列表
Apr 15 #Javascript
关闭浏览器窗口弹出提示框并且可以控制其失效
Apr 15 #Javascript
使用JavaScript的ActiveXObject对象检测应用程序是否安装的方法
Apr 15 #Javascript
You might like
PHP5 安装方法
2006/10/09 PHP
轻松修复Discuz!数据库
2008/05/03 PHP
PHP处理Oracle的CLOB实例
2014/11/03 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
php实现图片上传时添加文字和图片水印技巧
2020/04/18 PHP
PHP培训要多少钱
2017/06/06 PHP
PHP自定义序列化接口Serializable用法分析
2017/12/29 PHP
javascript 定义初始化数组函数
2009/09/07 Javascript
js创建对象的几种常用方式小结(推荐)
2010/10/24 Javascript
Flexigrid在IE下不显示数据的有效处理方法
2014/09/04 Javascript
JQuery点击行tr实现checkBox选中的简单实例
2016/05/26 Javascript
jQuery EasyUI API 中文帮助文档和扩展实例
2016/08/01 Javascript
Vue中自定义全局组件的实现方法
2017/12/08 Javascript
Vue动态组件与异步组件实例详解
2019/02/23 Javascript
Angular Excel 导入与导出的实现代码
2019/04/17 Javascript
使用vscode快速建立vue模板过程详解
2019/10/10 Javascript
在实例中重学JavaScript事件循环
2020/12/03 Javascript
Tornado服务器中绑定域名、虚拟主机的方法
2014/08/22 Python
解析Python中的生成器及其与迭代器的差异
2016/06/20 Python
浅谈python中的变量默认是什么类型
2016/09/11 Python
python 读取视频,处理后,实时计算帧数fps的方法
2018/07/10 Python
python多进程实现文件下载传输功能
2018/07/28 Python
Python实现常见的回文字符串算法
2018/11/14 Python
python多线程抽象编程模型详解
2019/03/20 Python
携程旅行网:中国领先的在线旅行服务公司
2017/02/17 全球购物
英国巧克力贸易公司:Chocolate Trading Company
2017/03/21 全球购物
西班牙土拨鼠床垫公司,感觉在云端:Marmota
2019/03/18 全球购物
The Outnet亚太地区:折扣设计师时装店
2019/12/05 全球购物
数控加工专业毕业生自荐信
2013/09/27 职场文书
毕业生物理教师求职信
2013/10/17 职场文书
公司财务自我评价分享
2013/12/17 职场文书
人事任命书怎么写
2014/06/05 职场文书
教师群众路线心得体会
2014/11/04 职场文书
2014年培训工作总结范文
2014/11/27 职场文书
人事主管岗位职责
2015/02/04 职场文书
一文搞懂Redis中String数据类型
2022/04/03 Redis