定义类
class Person {
name:string;
age:number;
getName():void{
console.log(this.name);
};
constructor() {
this.age = 18
}
}
let p1 = new Person();
p1.name='张三'
p1.getName();
console.log(p1.name)
console.log(p1.age)
存取器 getter setter
- 在 TypeScript 中,我们可以通过存取器来改变一个类中属性的读取和赋值行为
-
构造函数 主要用于初始化类的成员变量属性 类的对象创建时自动调用执行 没有返回值
class User {
myname:string;
constructor(myname: string) {
this.myname = myname;
}
get name() {
return this.myname;
}
set name(value) {
this.myname = value;
}
}
let user = new User('张三');
user.name = '李四';
console.log(user.name);
参数属性 public
- 把属性赋给
class实例,变为实例属性
class User {
constructor(public name: string) {}
}
let user = new User('1111');
console.log(user.name);
user.name = '111123333';
console.log(user.name);
只读属性 readonly
readonly修饰的变量只能在构造函数中初始化
class Animal {
public readonly name: string
constructor(name:string) {
this.name = name;
}
changeName(name:string){
// this.name = name;//报错 只读属性 只能在构造函数中赋值 或者初始化赋值
}
}
let a = new Animal('dog');
a.changeName('cat');
继承 class 子类 extends 父类
- 子类继承父类后子类的实例就拥有了父类中的属性和方法,可以增强代码的可复用性
- 子类不可继承父类的静态方法和属性
- 将子类公用的方法抽出来放在父类中,自己的特殊逻辑放在子类中重写父类的逻辑
- 派生类的构造函数必须包含
super调用
class User {
name:string;
age: number;
sex:string = 'man';
constructor(name: string, age:number) {
this.name = name;
this.age = age;
}
getName() {
return this.name
}
setName(newName: string){
this.name = newName
}
}
class Student extends User {
stuNo: number;
constructor(name: string, age: number, stuNo: number){//派生类的构造函数必须包含 "super" 调用
super(name, age)
this.stuNo = stuNo
}
getStuNo(){
return this.stuNo
}
setStuNo(newStuNo: number){
this.stuNo = newStuNo
}
}
let s = new Student('xiuli',18,1)
console.log(s.sex)
类中的修饰符
public自己 自己的子类 和其他类都可以访问protected受保护的 自己和自己的子类能访问, 其他类不能访问private私有的 只能自己访问,自己的子类不能访问,其他更不行
class User {
name:string;
protected age: number;
protected sex:string = 'man';
private amount:number;
constructor(name: string, age:number) {
this.name = name;
this.age = age;
}
getName() {
return this.name
}
setName(newName: string){
this.name = newName
}
}
class Student extends User {
stuNo: number;
constructor(name: string, age: number, stuNo: number){//派生类的构造函数必须包含 "super" 调用
super(name, age)
this.stuNo = stuNo
}
getStuNo(){
// console.log(this.amount)
return this.stuNo
}
setStuNo(newStuNo: number){
this.stuNo = newStuNo
}
}
let s = new Student('xiuli',18,1)
// console.log(s.sex)
静态属性 静态方法 static
static类属性; 其他属性属于实例属性prototype
class User {
name:string;
age: number;
sex:string = 'man';
static amount:number;
constructor(name: string, age:number) {
this.name = name;
this.age = age;
}
static getAmount () {
return User.amount
}
getName() {
return this.name
}
setName(newName: string){
this.name = newName
}
}
let a = new User('x',1)
a.name = 'qq'
// a.amount = 1;//报错
User.amount = 2
console.log(User.getAmount())
装饰器
- 装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或者参数上,可以修改类的行为
- 常见的装饰器有类装饰器、属性装饰器、方法装饰器和参数装饰器
- 装饰器的写法分为普通装饰器和装饰器工厂(装饰器带参数,在原有装饰器的基础上,设置外部变量)
类装饰器
- 类装饰器在类声明之前声明,用来监视、修改或替换类定义
namespace a {
interface Person {
name: string;
eat: any
}
function enhancer(target: any) {
target.prototype.name = 'xiuli';
target.prototype.eat = function () {
console.log('eat');
}
}
@enhancer
class Person {
constructor() { }
}
let p = new Person();
console.log(p.name);
p.eat();
}
namespace b {
interface Person {
name: string;
eat: any
}
function enhancer(name: string) {
return function enhancer(target: any) {
target.prototype.name = name;
target.prototype.eat = function () {
console.log('eat');
}
}
}
@enhancer('xiuli')
class Person {
constructor() { }
}
let p = new Person();
console.log(p.name);
p.eat();
}
namespace c {
interface Person {
name: string;
eat: any
}
function enhancer(target: any) {
return class {
name: string = 'li'
eat() {
console.log('吃饭饭');
}
}
}
@enhancer
class Person {
constructor() { }
}
let p = new Person();
console.log(p.name);
p.eat();
}
属性装饰器 方法装饰器
- 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
- 属性装饰器用来装饰属性
- 第一个参数对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
- 第二个参数是属性的名称
- 方法装饰器用来装饰方法
- 第一个参数对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 第二个参数是方法的名称
- 第三个参数是方法描述符
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
namespace d {
function upperCase(target: any, propertyKey: string) {
let value = target[propertyKey];
const getter = function () {
return value;
}
// 用来替换的setter
const setter = function (newVal: string) {
value = newVal.toUpperCase()
};
// 替换属性,先删除原先的属性,再重新定义属性
if (delete target[propertyKey]) {
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,//当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。默认为 false。
configurable: true,//当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
});
}
}
function noEnumerable(target: any, property: string, descriptor: PropertyDescriptor) {
console.log('target.getName', target.getName);
console.log('target.getAge', target.getAge);
descriptor.enumerable = true;
}
function toNumber(target: any, methodName: string, descriptor: PropertyDescriptor) {
let oldMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
args = args.map(item => parseFloat(item));
return oldMethod.apply(this, args);
}
}
class Person {
@upperCase
name: string = 'zhufeng'
public static age: number = 10
constructor() { }
@noEnumerable
getName() {
console.log(this.name);
}
@toNumber
sum(...args: any[]) {
return args.reduce((accu: number, item: number) => accu + item, 0);
}
}
let p = new Person();
for (let attr in p) {
console.log('attr=', attr);
}
console.log('static:age', Person.age)
p.name = 'jiagou';
p.getName();
console.log(p.sum("1", "2", "3"));
}
执行结果
target.getName function () {
console.log(this.name);
}
target.getAge undefined
attr= getName
attr= sum
attr= name
static:age 10
JIAGOU
6
参数装饰器
- 会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元数据
- 第一个参数对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
- 第二个参数是函数的名称
- 第三个参数是在函数列表中的索引
namespace d {
interface Person {
age: number;
}
function addAge(target: any, methodName: string, paramsIndex: number) {
console.log(target);
console.log(methodName);
console.log(paramsIndex);
target.age = 10;
}
class Person {
login(username: string, @addAge password: string) {
console.log(this.age, username, password);
}
}
let p = new Person();
p.login('xiuli', '123456')
}
运行结果
Person { login: [Function] }
login
1
10 'xiuli' '123456'
装饰器执行顺序
- 有多个参数装饰器时:从最后一个参数依次向前执行
- 方法和方法参数:参数装饰器先执行
- 类装饰器总是最后执行
- 方法和属性装饰器,谁在前面谁先执行。因为参数属于方法的一部分,所以参数会一致紧挨着方法执行
- 方法中的参数装饰器:从最后一个参数一次向前执行
namespace e {
function Class1Decorator() {
return function (target: any) {
console.log("类1装饰器");
}
}
function Class2Decorator() {
return function (target: any) {
console.log("类2装饰器");
}
}
function MethodDecorator() {
return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
console.log("方法装饰器");
}
}
function Param1Decorator() {
return function (target: any, methodName: string, paramIndex: number) {
console.log("参数1装饰器");
}
}
function Param2Decorator() {
return function (target: any, methodName: string, paramIndex: number) {
console.log("参数2装饰器");
}
}
function PropertyDecorator(name: string) {
return function (target: any, propertyName: string) {
console.log(name + "属性装饰器");
}
}
@Class1Decorator()
@Class2Decorator()
class Person {
@PropertyDecorator('name')
name: string = 'xiuli';
@PropertyDecorator('age')
age: number = 10;
@MethodDecorator()
greet(@Param1Decorator() p1: string, @Param2Decorator() p2: string) { }
}
}
执行结果
name属性装饰器
age属性装饰器
方法装饰器
参数2装饰器
参数1装饰器
类2装饰器
类1装饰器
抽象类
- 描述一种抽象的概念,无法被实例化,只能被继承
- 无法创建抽象类的实例
- 抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且必须实现
abstract class Animal {
name:string;
setName(){
this.name = '狗'
}
abstract getName(): string
}
class Cat extends Animal{
getName(): string {
return this.name
}
}
let cat = new Cat();
cat.name = '猫'
cat.setName()
console.log(cat.getName())
// let a = new Animal();//报错 抽象类不能被实例化
抽象方法
- 抽象类和方法不包含具体实现,必须在子类中实现
- 抽象方法只能出现在抽象类中
- 子类可以对抽象类进行不同的实现
abstract class Animal{
abstract speak():void;
}
class Dog extends Animal{
speak(){
console.log('小狗汪汪汪');
}
}
class Cat extends Animal{
speak(){
console.log('小猫喵喵喵');
}
}
let dog=new Dog();
let cat=new Cat();
dog.speak();
cat.speak();
重写(override)vs 重载(overload)
- 重写是指子类重写继承来自父类中的方法
- 重载是指为同一个函数提供多个类型定义
class Animal{
speak(word:string):string{
return '动作叫:'+word;
}
}
class Cat extends Animal{
speak(word:string):string{
return '猫叫:'+word;
}
}
let cat = new Cat();
console.log(cat.speak('hello'));
//--------------------------------------------
function double(val:number):number
function double(val:string):string
function double(val:any):any{
if(typeof val == 'number'){
return val *2;
}
return val + val;
}
let r = double(1);
console.log(r);
继承 vs 多态
- 继承:子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
- 多态:由继承所产生了相关的不同的类,对同一个方法可以有不同的行为
class Animal{
speak(word:string):string{
return 'Animal: '+word;
}
}
class Cat extends Animal{
speak(word:string):string{
return 'Cat:'+word;
}
}
class Dog extends Animal{
speak(word:string):string{
return 'Dog:'+word;
}
}
let cat = new Cat();
console.log(cat.speak('hello'));
let dog = new Dog();
console.log(dog.speak('hello'));