开始
定义了一些属性的Person()构造器。
1 | function Person(first, last, age, gender, interests) { |
所有的方法都定义在构造器的原型上,比如:
1 | Person.prototype.greeting = function() { |
比如我们想要创建一个 Teacher
类,就像我们前面在面向对象概念解释时用的那个一样。这个类会继承 Person
的所有成员,同时也包括:
- 一个新的属性,
subject
——这个属性包含了教师教授的学科。 - 一个被更新的
greeting()
方法,这个方法打招呼听起来比一般的greeting()
方法更正式一点。
定义 Teacher() 构造器函数
我们要做的第一件事是创建一个 Teacher()
构造器——将下面的代码加入到现有代码之下:
1 | function Teacher(first, last, age, gender, interests, subject) { |
这在很多方面看起来都和 Person
的构造器很像,但是这里有一些我们从没见过的奇怪玩意—— call()
函数。基本上,这个函数允许您调用一个在这个文件里别处定义的函数。第一个参数指明了在您运行这个函数时想对“ this
”指定的值,也就是说,您可以重新指定您调用的函数里所有“ this
”指向的对象。其他的变量指明了所有目标函数运行时接受的参数。
所以在这个例子里,我们很有效的在 Teacher()
构造函数里运行了 Person()
构造函数(见上文),得到了和在 Teacher()
里定义的一样的属性,但是用的是传送给 Teacher()
,而不是 Person()
的值(我们简单使用这里的 this
作为传给 call()
的 this
,意味着 this
指向 Teacher()
函数)。
在构造器里的最后一行代码简单地定义了一个新的subject属性,这将是教师会有的,而一般人没有的属性。
设置 Teacher() 的原型和构造器引用
上面只是继承了 Person()
的属性,但是其方法在其原型中,我们并没有继承。
- 在控制台输入以下代码
1 | Teacher.prototype = Object.create(Person.prototype); |
上面我们通过 create
方法用 Person.prototype
生成一个对象,并将其赋值给 Teacher.prototype
。
2. 但是上面的代码导致了一个问题,即 Teacher
原型的构造器变成了 Person
原型的构造器,这是不对的,通过下面的方式进行修改。
1 | Object.defineProperty(Teacher.prototype, 'constructor', { |
向 Teacher() 添加一个新的 greeting() 函数
为了完善代码,您还需在构造函数 Teacher()
上定义一个新的函数 greeting()
。最简单的方法是在 Teacher
的原型上定义它—把以下代码添加到您代码的底部:
1 | Teacher.prototype.greeting = function() { |
范例尝试
在控制台输入以下代码创建一个 Teacher()
对象实例。
1 | var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics'); |
试一下您的老师实例的属性和方法:
1 | teacher1.name.first; |
前面两个进入到从 Person()
的构造器 继承的属性和方法,后面两个则是只有 Teacher()
的构造器才有的属性和方法。
ECMAScript 2015 Classes
ECMAScript 2015 在JavaScript中引入了 class
语法,这让我们更方便地去写一个可以复用的类,并且这与 C++ 和 Java 中的类更加相似。下面这个部分,我们将上面 Person 和 Teacher 的例子从原型继承转到类。
下面是用 class
语法的 Person 样例
1 | class Person { |
constructor()
方法定义了代表Person
类的构造器函数greeting()
和farewell()
都是类方法,任何与该类有关的方法都可以定义在class
里。
然后我们就可以定义对象实例
1 | let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']); |
class语法的继承
使用 extends
关键字去创建一个子类,去告诉 JavaScript 我们基于的类。
1 | class Teacher extends Person { |
但这样,运行之前定义 Teacher
对象实例的语句会报如下错误。
1 | Uncaught ReferenceError: Must call super constructor in derived class before |
这时因为,我们没有调用 Person()
的构造方法。
所以,我们对其使用 super()
操作符进行修改。
1 | class Teacher extends Person { |
接下来,实例化 Teacher()
对象就没有什么问题了。
1 | let snape = new Teacher('Severus', 'Snape', 58, 'male', ['Potions'], 'Dark arts', 5); |
Getters and Setters
对于对象的属性的获取与修改,我们一般都会使用 Getters
和 Setters
来完成。我们修改 Teacher
类。
1 | class Teacher extends Person { |
我们使用 _
去创建一个私有属性。