在ES6之前,JS没有class关键字,JS的面向对象和继承也是面试中常见的问题.之前接触过PHP面向对象的话,在看这部分内容会觉得很多相近相似的内容
1.类
类是描述一类相同事物特征和行为的抽象.描述一个类需要两部分,属性描述特征,方法描述行为,并且用class来修饰,这样构成了一个类,类相当于提供了一个模板,快速的根据模板创建的对象.先看一个类的例子
class Person{
name:string;
constructor(name:string) {
this.name = name;
}
sayHi(){
return this.name;
}
}
name是属性,constructor是构造函数,构造函数在JS的面向对象里也存在,初始化对象自定义内容的函数,sayHi是方法,方法里返回name属性的内容,整体写法跟JS的面向对象类似,获取值的时候也是使用this关键字.接下来看一下解析的.js文件里的内容
var Person = (function () {
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function () {
return this.name;
};
return Person;
}());
使用的就是JS的构造函数,在原型上添加了一个sayHi方法,还是比较好理解的
2.继承
TypeScript里的继承跟PHP还是比较相似的,相当于是子类对父类进行功能和内容的扩张,使用的关键字也是extends,延展.
// 父类
class Person{
name:string;
constructor(name: string) {
this.name = name;
}
move(meter: number = 0) {
console.log(\`${this.name} moved ${meter}m.\`);
}
}
// 子类
class Student extends Person {
age:number;
constructor(name: string, age:number) {
super(name);
this.age = age;
}
move(meter = 5) {
console.log("测试...");
super.move(meter);
}
}
Student继承父类Person,子类会继承父类所有特征和行为,子类的构造函数里,如果子类和父类同时声明构造函数,子类创建对象的时候优先使用自己类里的构造函数,如果还想使用父类的构造函数,需要在子类的构造函数里使用super(),而且这句话要放在子类构造函数的最上面,否则会报错,只有构造函数需要注意这个问题.
代码里演示了子类重写了继承过来的move方法,如果还想调用父类功能,可以在方法里视同super.move(),通过super来调用父类的方法,保留功能.
3.修饰符
修饰符的作用就是用来限制属性和方法使用的范围,有三种修饰符,公有public,私有private,被保护的protected
1.public 公有的
方法和属性默认的修饰符就是public,对象在使用它修饰的属性和方法时,可以直接在用.的方式进行调用,使用范围是最大的
class Person{
public name:string;
constructor(name: string) { this.name = name; }
public move(meter: number = 0) {
console.log(\`${this.name} moved ${meter}m.\`);
}
}
2.被保护的 protected
被protected修饰的属性和方法,限制了属性和方法的使用范围,只能在类和子类中使用,如果在类外部调用,会报错
class Person{
protected name:string;
constructor(name: string) { this.name = name; }
protected move(meter: number = 0) {}
}
class Student extends Person {
age:number;
constructor(name: string, age:number) {
super(name);
this.age = age;
}
move(meter = 5) {
super.move();
console.log(this.name); // 子类的内部可以使用
}
}
let an = new Person("张三");
an.move(); // 报错,在类的外部使用
类的内部,就值在类对应的大括号里,protected修饰的属性方法可以使用,这样限制了属性和方法的使用范围,使用受限,相对的安全性更好
3.私有的 private
private的使用范围更小了,被限制到只能在自己类的内容使用,连子类都不能使用,当时private是使用最多的,因为最大化的减少了使用范围,能更好规避一些不必要的使用出现的问题,更安全
class Person{
private name:string;
constructor(name: string) { this.name = name; }
private move(meter: number = 0) {}
}
class Student extends Person {
age:number;
constructor(name: string, age:number) {
super(name);
this.age = age;
}
move(meter = 5) {
super.move(); // 报错,子类的内部也不能使用
console.log(this.name); // 报错,子类的内部也不能使用
}
}
当这样的类创建的对象,想获取属性的值的时候,需要用setters和getters对属性进行操作
<pre>
class Person{
private _name:string;
constructor(name: string) { this.name = name; }
set name(newName:string){
this._name = newName;
}
get name(){
return this._name;
}
}
let per = new Person("张三");
per.name = "龙哥";
console.log(per.name);
</pre>
在使用设置器setters和访问器getters时,属性名会习惯的加一个下划线,用来和另个方法名进行区分,这种方式和iOS里的属性写法一样,对象可以直接使用,用法跟之前一样,只不过本质是用函数来赋值.在使用的时候需要注意,编译器至少是ES5或者更高,否则会报错
4.静态属性
之前的属性都是由对象来使用,必须实例化之后,才能使用.静态属性不同,这类属性都用在类本身上.用static关键词来修饰
<pre>
class Grid {
static origin = {x: 100, y: 10};
test():void{
console.log(Grid.origin.x);
}
}
let obj = new Grid();
obj.test();
console.log(Grid.origin.x);
console.log(obj.origin.x); // 报错,对象不能使用静态属性
</pre>
5.抽象类
抽象类一般作为其他派生类的基类使用,如果通过这个类进行对象创建,在控制台会报错,内容就是在对一个抽象类进行实例化操作.抽象类用关键词abstract进行修饰,抽象类里的正常方法具体的实现,用abstract修饰的抽象方法需要在子类中实现.抽象类跟接口类似,都是定义方法签名,不包含方法体.
<pre>
abstract class Person {
constructor(public name: string) {}
printName(): void {
console.log('name: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class Animal extends Person {
constructor(name:string) {
super(name);
}
printMeeting(): void {
console.log('嗯嗯');
}
generateReports(): void {
console.log('饿了');
}
}
let an = new Animal("龙哥");
an.printMeeting();
console.log(an.name);
</pre>