TypeScript基础入门 - 类 - 公共、私有与受保护的修饰符

转载node

TypeScript基础入门 - 类 - 公共、私有与受保护的修饰符

项目实践仓库git

https://github.com/durban89/typescript_demo.git
tag: 1.1.1

为了保证后面的学习演示须要安装下ts-node,这样后面的每一个操做都能直接运行看到输出的结果。github

npm install -D ts-node

后面本身在练习的时候能够这样使用typescript

npx ts-node 脚本路径

公共,私有与受保护的修饰符

默认为 public

在上篇文章【TypeScript基础入门 - 类 - 继承】的例子里,咱们能够自由的访问程序里定义的成员。 若是你对其它语言中的类比较了解,就会注意到咱们在以前的代码里并无使用 public来作修饰;例如,C#要求必须明确地使用 public指定成员是可见的。 在TypeScript里,成员都默认为public。你也能够明确的将一个成员标记成public。 咱们能够用下面的方式来实现一个Animal类:npm

class Animal {
    public name: string;
    public constructor(theColor: string) {
        this.name = theColor;
    }

    public move(distanceMeter: number = 0) {
        console.log(`${this.name} moved ${distanceMeter}m`);
    }
}

理解 private

当成员被标记成 private时,它就不能在声明它的类的外部访问。好比:函数

class Animal {
    private name: string;
    public constructor(theName: string) {
        this.name = theName;
    }

    public move(distanceMeter: number = 0) {
        console.log(`${this.name} moved ${distanceMeter}m`);
    }
}

new Animal('small cat').name;

运行后获得以下结果学习

$ npx ts-node src/classes_3.ts
⨯ Unable to compile TypeScript:
src/classes_3.ts(12,25): error TS2341: Property 'name' is private and only accessible within class 'Animal'.

TypeScript使用的是结构性类型系统。 当咱们比较两种不一样的类型时,并不在意它们从何处而来,若是全部成员的类型都是兼容的,咱们就认为它们的类型是兼容的。this

然而,当咱们比较带有 private或 protected成员的类型的时候,状况就不一样了。 若是其中一个类型里包含一个 private成员,那么只有当另一个类型中也存在这样一个 private成员, 而且它们都是来自同一处声明时,咱们才认为这两个类型是兼容的。 对于 protected成员也使用这个规则。下面来看一个例子,更好地说明了这一点:spa

class Animal {
    private name: string;
    public constructor(theName: string) {
        this.name = theName;
    }

    public move(distanceMeter: number = 0) {
        console.log(`${this.name} moved ${distanceMeter}m`);
    }
}

class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }
}

class Person {
    private name: string;
    
    public constructor(theName: string) {
        this.name = theName;
    }

    public move(distanceMeter: number = 0) {
        console.log(`${this.name} moved ${distanceMeter}m`);
    }
}

let animal = new Animal('animal');
let dog = new Dog('dog');
let person = new Person('person');

animal = dog
animal = person;

运行后获得以下结果code

$ npx ts-node src/classes_3.ts
⨯ Unable to compile TypeScript:
src/classes_3.ts(35,1): error TS2322: Type 'Person' is not assignable to type 'Animal'.
  Types have separate declarations of a private property 'name'.

这个例子中有Animal和Dog两个类, Dog是 Animal类的子类。还有一个Person类,其类型看上去与Animal是相同的。 咱们建立了几个这些类的实例,并相互赋值来看看会发生什么。由于Animal和Dog共享了来自Animal里的私有成员定义private name: string,所以它们是兼容的。 然而 Person却不是这样。当把Person赋值给Animal的时候,获得一个错误,说它们的类型不兼容。尽管Person里也有一个私有成员name,但它明显不是Animal里面定义的那个。

理解 protected

protected修饰符与 private修饰符的行为很类似,但有一点不一样, protected成员在派生类中仍然能够访问。例如:

class Person {
    protected name: string;
    constructor(name: string) {
        this.name = name;
    }
}

class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }

    getWorkInfo() {
        return `我叫${this.name},我工做在${this.department}`;
    }
}

let aEmployee = new Employee('durban', '华盛顿');
console.log(aEmployee.getWorkInfo());
console.log(aEmployee.name);

运行后获得的结果以下

$ npx ts-node src/classes_3.ts
⨯ Unable to compile TypeScript:
src/classes_3.ts(23,23): error TS2445: Property 'name' is protected and only accessible within class 'Person' and its subclasses.

注意,咱们不能在 Person类外使用 name,可是咱们仍然能够经过 Employee类的实例方法访问,由于 Employee是由 Person派生而来的。构造函数也能够被标记成 protected。 这意味着这个类不能在包含它的类外被实例化,可是能被继承。好比:

class Person {
    protected name: string;
    protected constructor(name: string) {
        this.name = name;
    }
}

class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name);
        this.department = department;
    }

    getWorkInfo() {
        return `我叫${this.name},我工做在${this.department}`;
    }
}

let aEmployee = new Employee('durban', '华盛顿');
let aPerson = new Person('Sakuro');

运行后获得以下错误

$ npx ts-node src/classes_3.ts
⨯ Unable to compile TypeScript:
src/classes_3.ts(22,15): error TS2674: Constructor of class 'Person' is protected and only accessible within the class declaration.

readonly修饰符

你可使用 readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。以下:

class Person {
    readonly name: string;
    constructor(name: string) {
        this.name = name;
    }
}

const aPerson = new Person('Xiaowang');
aPerson.name = 'Xiaoli';

运行后获得以下

$ npx ts-node src/classes_3.ts
⨯ Unable to compile TypeScript:
src/classes_3.ts(9,9): error TS2540: Cannot assign to 'name' because it is a constant or a read-only property.

参数属性

在上面的例子中,咱们不得不定义一个受保护的成员 name和一个构造函数参数 theName在 Person类里,而且马上给 name和 theName赋值。 这种状况常常会遇到。 参数属性能够方便地让咱们在一个地方定义并初始化一个成员。 下面的例子是对以前 Animal类的修改版,使用了参数属性:

class Animal {
    public constructor(private name: string) { }

    public move(distanceMeter: number = 0) {
        console.log(`${this.name} moved ${distanceMeter}m`);
    }
}

注意看咱们是如何舍弃了 theName,仅在构造函数里使用 private name: string参数来建立和初始化 name成员。 咱们把声明和赋值合并至一处。

参数属性经过给构造函数参数添加一个访问限定符来声明。 使用 private限定一个参数属性会声明并初始化一个私有成员;对于 public和 protected来讲也是同样。

本实例结束实践项目地址

https://github.com/durban89/typescript_demo.git
tag: 1.1.2
相关文章
相关标签/搜索