本节是第四讲的第十四小节,上一节我们为大家介绍了JAVAScript对象的基础概念,本节为大家介绍JavaScrip面向对象编程(OOP)以及构造函数等概念。
面向对象的程序设计(Object-oriented programming,OOP)
OOP 的基本思想是:在程序里,我们通过使用对象去构建现实世界的模型,把原本很难(或不可)能被使用的功能,简单化并提供出来,以供访问。对象可以包含相关的数据和代码,这些数据和代码用于表示 你所建造的模型是什么样子,以及拥有什么样的行为或功能。对象包(object package,或者叫命名空间 namespace)存储(官方用语:封装)着对象的数据(常常还包括函数),使数据的组织和访问变得更容易了;对象也常用作 数据存储体(data stores),用于在网络上运输数据,十分便捷。
定义一个对象模板(Object template)
让我们来考虑一个简单的程序,它可以显示一个学校的学生和老师的信息.在这里我们不讨论任何程序语言,我们只讨论 OOP 思想。
首先,我们可以回到上一节拿到定义好属性和方法的Person对象。对于一个人(person)来说,我们能在他们身上获取到很多信息(他们的住址,身高,鞋码,基因图谱,护照信息,显著的性格特征等等),然而,我们仅仅需要他们的名字,年龄,性别,兴趣 这些信息,然后,我们会基于他们的这些信息写一个简短的介绍关于他们自己,在最后我们还需要教会他们打招呼。以上的方式被称为抽象-为了我们编程的目标而利用事物的一些重要特性去把复杂的事物简单化。
在一些面向对象的语言中,我们用类(class)的概念去描述一个对象(您在下面就能看到JavaScript使用了一个完全不同的术语)-类并不完全是一个对象,它更像是一个定义对象特质的模板。
创造一个真正的对象
从上面我们创建的class中, 我们能够基于它创建出一些对象 - 一些拥有class中属性及方法的对象。基于我们的Person类,我们可以创建出许许多多的真实的人:
当一个对象需要从类中创建出来时,类的构造函数就会运行来创建这个实例。这种创建对象的过程我们称之为实例化-实例对象被类实例化。
具体的子类
在这个例子里,我们不想要泛指的人,我们想要像老师和学生这样类型更为具体的人。在 OOP 里,我们可以创建基于其它类的新类,这些新的子类可以继承它们父类的数据和功能。比起复制来说这样能够使用父对象共有的功能。如果类之间的功能不同,你可以根据需要定义专用的特征。
这是非常有用的,老师和学生具有一些相同的特征比如姓名、性别、年龄,因此只需要定义这些特征一次就可以了。您可以在不同的类里分开定义这些相同的特征,这样该特征会有一个不同的命名空间。比如,一个学生的 greeting 可以是 "Yo, I'm [firstName]" (例子 Yo, I'm Sam),老师的可能会正式一些,比如"Hello, my name is [Prefix] [lastName]" (例子 Hello, My name is Mr Griffiths)。
Note:多态(polymorphism)—这个高大上的词正是用来描述多个对象拥有实现共同方法的能力。
具体的对象
现在可以根据子类创建对象。
构建函数(Constructor Functions)和对象
有些人认为 JavaScript 不是真正的面向对象的语言,比如它没有像许多面向对象的语言一样有用于创建class类的声明。JavaScript 用一种称为构建函数(constructor functions)的特殊函数来定义对象和它们的特征。构建函数非常有用,因为很多情况下您不知道实际需要多少个对象(实例)。构建函数提供了创建您所需对象(实例)的有效方法,将对象的数据和特征函数按需联结至相应对象。
不像“经典”的面向对象的语言,从构建函数创建的新实例的特征并非全盘复制,而是通过一个叫做原形链的参考链链接过去的。所以这并非真正的实例,严格的讲, JavaScript 在对象间使用和其它语言的共享机制不同。
Note:“经典”的面向对象的语言就像上面提到的,OOP 可能很快就变得非常复杂,JavaScript 找到了在不变的特别复杂的情况下利用面向对象的优点的方法。
一个简单的例子
function Person(name) {
this.name = name;
this.greeting = function() {
alert('Hi! I'm ' + this.name + '.');
};}
var person1 = new Person('Bob');
var person2 = new Person('Sarah');
person1.name
person1.greeting()
person2.name
person2.greeting()
这个构建函数是 JavaScript 版本的类。您会发现,它只定义了对象的属性和方法,除了没有明确创建一个对象和返回任何值和之外,它有了您期待的函数所拥有的全部功能。这里使用了this关键词,即无论是该对象的哪个实例被这个构建函数创建,它的 name 属性就是传递到构建函数形参name的值,它的 greeting() 方法中也将使用相同的传递到构建函数形参name的值。
Note: 一个构建函数通常是大写字母开头,这样便于区分构建函数和普通函数。
页面上有两个对象,每一个保存在不同的命名空间里,当您访问它们的属性和方法时,您需要使用person1或者person2来调用它们。尽管它们有着相同的name属性和 greeting()方法它们是各自独立的,所以相互的功能不会冲突。注意它们使用的是自己的 name 值,这也是使用 this 关键字的原因,它们使用的从实参传入形参的自己的值,而不是其它的什么值。
创建最终的构造函数
function Person(first, last,gender) {
this.name = {
'first': first, 'last': last
};
this.gender = gender;
this.greeting = function() {
alert('Hi! I'm ' + this.name.first + '.');
};
}
let person1 = new Person('Bob', 'Smith', 'male');
Object()构造函数
到现在为止,我们了解到了两种不同的创建对象的方式 —— 声明一个对象的语法, 与使用构造函数。使用Object()构造函数来创建一个新对象。 是的, 一般对象都有构造函数,它创建了一个空的对象。
常见有两种创建方式,第一种如下:
var person1 = new Object();
person1.name = 'Chris';
person1['gender'] = 'male';
person1.greeting = function() {
alert('Hi! I'm ' + this.name + '.');
}
还有一种如下:
var person1 = new Object({
name : 'Chris',
gender: 'male',
greeting : function() {
alert('Hi! I'm ' + this.name + '.');
}});
JavaScript有个内嵌的方法create(), 它允许您基于现有对象创建新的对象。person2是基于person1创建的, 它们具有相同的属性和方法。这非常有用, 因为它允许您创建新的对象而无需定义构造函数。缺点是比起构造函数,浏览器在更晚的时候才支持create()方法(IE9, IE8 或甚至以前相比), 加上一些人认为构造函数让您的代码看上去更整洁 —— 您可以在一个地方创建您的构造函数, 然后根据需要创建实例, 这让您能很清楚地知道它们来自哪里。例如:
var person2 = Object.create(person1);
以上内容部分摘自视频课程04网页游戏编程JavaScript-14面向对象编程,更多示例请参见网站示例。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。