TypeScript 由 Microsoft 开发,是一种开源的、面向对象的编程语言。当然,它是 JavaScript 的一个强大的语法超集,并改进了该语言的可选静态类型。其中最重要的一点就是TypeScript 支持面向对象的所有特性。
在JavaSript中,可以说一切皆为对象,当我们用面向对象的思想进行封装代码时,不论是用构造函数,对象,还是ES6新增的class时,其实本质上都是在使用JavaScript的Object对象,这就要求在进行一些比较复杂的对象封装时,需比较熟悉对象的原型链等原理,才能封装出简洁,易读,易扩展的对象。面向对象的三大特征为继承、封装、多态。JavaScript虽然可以模拟实现继承和封装,但无法良好的模拟实现多态。
ES5实现类代码示例:
// 定义一个Person类
function Person(name, age) {
this.name = name; // 公有属性
var privateAge = age; // 私有属性(通过闭包保存)
// 获取年龄的公共方法
this.getAge = function() {
return privateAge;
};
}
// 创建一个新的Person对象
var person1 = new Person("张三", 20);
console.log(person1.name); // 输出 "张三"
console.log(person1.age); // undefined (无法直接访问私有属性)
console.log(person1.getAge()); // 输出 20 (调用公共方法获取私有属性值)
ES6实现类代码示例:
class Person {
// 构造函数
constructor(name, age) {
this.name = name
this.age = age
}
// 方法
say(){
console.log('我能说话')
}
}
// 实例化
let zs = new Person('张三', 24)
// 实例化
let ls = new Person('李四', 24)
console.log(zs)
console.log(ls)
TS实现类代码示例:
class Person{
public name:string;
private age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
public setAge(age:number){
this.age = age;
}
public getAge():number{
return this.age;
}
}
let person = new Person("xiaoming",20);
console.log(person.name);
console.log(person.getAge());
ES6引入了类的概念,为 JavaScript 增加了面向对象编程的能力。ES6 中的类是一种语法糖,本质上仍然是基于原型的继承。使用类可以定义构造函数、实例方法和静态方法,并且支持继承和类之间的关系。TypeScript新增了类、接口、泛形等等这些特性。相比“灵活自由”的JavaScript式封装,运用这些特性将会使初学者写的代码更加规范,更易于阅读和扩展,降低了一些封装的门槛,同时也方便了一些熟悉面向对象编程的开发者进行开发,TypeScript相比ES6具有更强的类型系统和其他功能 ,并且而对于大型的项目开发,这种面向对象的开发方式能有助于团队合作,提高开发人员的工作效率。
?对于学过Java等面向对象的小伙伴来说,学习TypeScript是非常轻松的,接下来,我就从一下常见属性来讲解TypeScript面向对象特性。
定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):?
字段?:?字段是类里面声明的变量。字段表示对象的有关数据。
构造函数?:类实例化时调用,可以为类的对象分配内存。
方法?:?方法为对象要执行的操作。
class {
? ? ? ? [修饰符] 字段名:[字段类型];
? ? ? ? constructor([参数1:类型,....]){
? ? ? ? ? ? ? ? // 执行一些初始化操作
????????},
? ? ? ?[修饰符] 方法名([参数1:类型,....):返回值类型{
? ? ? ? ? ? ? ? // 方法体....
????????}
}
例如:
class Person{
public name:string;
private age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
public setAge(age:number){
this.age = age;
}
public getAge():number{
return this.age;
}
}
let person = new Person("xiaoming",20);
console.log(person.name);
console.log(person.getAge());
class User{
private name:string;
constructor(name:string){
this.name = name;
}
public setName(name:string):void{
this.name = name;
}
public getName():string{
return this.name;
}
}
class Admin extends User{
private password:string;
constructor(name:string,password:string){
super(name);
this.password = password;
}
public setPassword(password:string){
this.password = password;
}
public getPassword():string{
return this.password;
}
}
let user1 = new User("xujingliang");
console.log(user1.getName());
let admin = new Admin("xujingliang","123456")
console.log(admin.getName());
console.log(admin.getPassword());
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
重写是子类继承父类之后,方法名称,参数名称,返回值类型全部相同只能修改方法体中的相关操作。
重写的优点:在拥有父类方法特征的同时,自身也可以有一些特有的特征
class User{
private name:string;
constructor(name:string){
this.name = name;
}
public setName(name:string):void{
this.name = name;
}
public getName():string{
return this.name;
}
public say():string{
return "My name is "+this.name;
}
}
class Admin extends User{
private password:string;
constructor(name:string,password:string){
super(name);
this.password = password;
}
public setPassword(password:string){
this.password = password;
}
public getPassword():string{
return this.password;
}
public say():string{
return "My name is "+super.getName()+" and my password is "+this.password;
}
}
let user = new User("xujingliang");
console.log(user.say());
let admin = new Admin("xujingliang","123456")
console.log(admin.say());
上面的代码示例中,我们先定义了一个User用户类,又定义了一个Admin管理员类。Admin类继承User类,并对User类的say()方法进行重写。?
使用static生命的类字段或者方法不需要实例化对象,可以直接通过类名点字段名称或者类名点方法名称直接调用。
class Person{
public name:string;
private age:number;
static mark:string = "普通用户"
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
public setAge(age:number){
this.age = age;
}
public getAge():number{
return this.age;
}
}
console.log(Person.mark);
示例代码中,声明了一个static字段mark,直接使用Person.mark就可以访问。?
instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。
class User{
private name:string;
constructor(name:string){
this.name = name;
}
public setName(name:string):void{
this.name = name;
}
public getName():string{
return this.name;
}
}
class Admin extends User{
private password:string;
constructor(name:string,password:string){
super(name);
this.password = password;
}
public setPassword(password:string){
this.password = password;
}
public getPassword():string{
return this.password;
}
}
let user1 = new User("xujingliang");
let admin = new Admin("xujingliang","123456")
console.log(user1 instanceof User);
console.log(user1 instanceof Admin);
console.log(admin instanceof Admin);
console.log(admin instanceof User);
注意:示例代码中,Admin类继承User类,因此用Admin示例化的对象既属于User类有属于Admin类
类成员可访问性定义了类的成员允许在何处被访问。和Java一样TypeScript也为类成员提供了三种可访问性修饰符。
1. public:类的公有成员没有访问限制,可以在当前类的内部、外部以及派生类的内部访问。类的公有成员使用public修饰符标识。在默认情况下,类的所有成员都是公有成员。
2. protected:类的受保护成员允许在当前类的内部和派生类的内部访问,但是不允许在当前类的外部访问。类的受保护成员使用protected修饰符标识。
3. private:类的私有成员只允许在当前类的内部被访问,在当前类的外部以及派生类的内部都不允许访问。类的私有成员使用private修饰符标识。
类可以实现接口,使用关键字 implements,并将 interest 字段作为类的属性使用。
interface Person{
name:string
}
class User implements Person{
name:string;
constructor(name:string){
this.name = name;
}
public setName(name:string):void{
this.name = name;
}
public getName():string{
return this.name;
}
}
class Admin extends User{
private password:string;
constructor(name:string,password:string){
super(name);
this.password = password;
}
public setPassword(password:string){
this.password = password;
}
public getPassword():string{
return this.password;
}
}
let user1 = new User("xujingliang");
let admin = new Admin("xujingliang","123456")