es6 类的私有属性_ES6 Class 类总结

a92eed31e8b167ece1968192fe816d7f.png

ES6的class实际上是原型继承被底层隐藏起来了

如何使用ES5代码创建类:

// 飞机的构造函数
function Plane(numEngines) {
  this.numEngines = numEngines;
  this.enginesActive = false;
}

// 所有实例继承的方法
Plane.prototype.startEngins = function(){
  console.log('starting engins...');
  this.enginesActive = true;
}

const johnsonsPlane = new Plane(1);
johnsonsPlane.startEngines();

const tammysPlane = new Plane(4);
tammysPlane.startEngines();

Plane是一个构造函数,它将用来创建新的Plane对象,每个对象都可以访问Plane.prototype原型对象上的方法,这里的new有四个步骤:

  • 创建一个新的对象;
  • 将构造函数的作用域赋给新的对象;
  • 执行构造函数中的代码;
  • 返回这个新的对象;

ES6在底层帮你设置了所有的这些,用ES6重写:

class Plane {
  constructor (numEngines){
    this.numEngines = numEngines;
    this.enginesActive = false;
  }
  
  startEngins(){
    console.log('starting engines...');
    this.enginesActive = true;
  }
}


类只是一种函数,在类种,不用逗号来区分属性或方法,如果添加逗号,将会出现语法错误

静态方法

要添加静态方法,在方法前加关键字static

class Plane {
  constructor (numEngines){
    this.numEngines = numEngines;
    this.enginesActive = false;
  }
  
  // 静态方法,可直接调用Plane.badWeather([plane1, plane2])
  static badWeather(planes){
    for (plane of planes){
      plane.enginesActive = false;
    }
  }
  
  startEngins(){
    console.log('starting engines...');
    this.enginesActive = true;
  }
}

ES6 中的子类

我们使用superextends关键字扩展类,super必须在this之前被调用!

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

class Horse extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);


类从基类中继承了属性和方法,Snake是派生类,它派生自Animal基类,通过extends关键字,派生类称为子类,基类称为超类
子类包含了一个构造函数,它必须调用super(),它会执行基类的构造函数,而且,在构造函数里访问 this 属性之前,一定要调用super() ,这也是TypeScript强制执行的一条重要规则。

公有,私有于受保护的修饰符

默认为 public

在上面的例子里,我们可以自由访问程序里定义的成员,在TypeScript里,成员默认为public,你也可以明确的将一个成员标记成public

class Animal {
  public name: string;
  public constructor(theName: string){
    this.name = theName;
  }
  public move(distanceInMeters: number){
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}


还要注意的是,在构造函数的参数上使用public等同于创建了同名的成员变量

class Student {
    fullName: string;
    constructor(public firstName, public middleInitial, public lastName) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person : Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new Student("Jane", "M.", "User");

document.body.innerHTML = greeter(user);

理解private

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

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

new Animal('Cat').name; // 错误:’name‘是私有的

理解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;
  }
  
  public getElevatorPitch() {
    return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  }
}

let howard = new Employe("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // 错误


注意:我们不能在Person类外使用name,但是我们仍然可以通过Employee类的示例方法访问,因为Employee是由Person派生而来

构造函数也可以被标记成 protected。 这意味着这个类不能在包含它的类外被实例化,但是能被继承。比如,

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

// Employee 能够继承 Person
class Employee extends Person {
    private department: string;

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

    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // 错误: 'Person' 的构造函数是被保护的.

readonly修饰符

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

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.


完整的例子:

class TestClass {
  constructor(name: string, private address: string, public city){
  
   testMethod(){
     console.log(this.name)// Compiler error: property 'name' does not exist on type 'TestClass'.
     console.log(this.address);
     console.log(this.city);
   }
  }
}

const testClass = new TestClass('Johnson', '8 gaoke road', 'NanNing');
testClass.testMethod();

console.log(testClass.name); // Compiler error: property 'name' does not exist on type 'TestClass'.
console.log(testClass.address); // Compiler error: 'address' is private and only accessible within class 'TestClass'.
console.log(testClass.city) // NanNing

TypeScript 参数属性

先看例子:

class Octopus {

  // 只读属性必须在声明时或者构造函数里被初始化
  readonly name: string;
  readonly numberOfLegs: number = 8;
  
  constructor (theName: string) {
    this.name = theName;
  }
}

let dad = new Octopus("Man whti the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误!name是只读的

Octopus定义了一个只读成员name和一个参数为theName的构造函数,并且立刻将theName的值赋给name,这种情况经常会遇到。参数属性可以方便的让我们在一个地方定义并初始化一个成员,重构如下:

class Octopus {
  readonly numberOfLegs: number = 8;
  constructor(readonly name: string){
  
  }
}


我们舍弃了theName,仅在构造函数中使用readonly name: string参数来创建和初始化name成员,把声明和赋值并至一处。

参数属性通过给构造函数参数前面添加一个访问限定符来声明使用private限定一个参数属性会声明并初始化一个私有成员;对于publicprotected来说也是一样。

类的优势

  • 创建的函数编写的代码变少了
  • 在类里面,可以清晰的指定构造函数
  • 类需要的所有代码都包含在类声明中,可以设定一切内容,不需要向原型一个一个去添加方法

注意

  • class只是语法糖
  • class是原型继承的抽象形式
  • 在创建类的新实例,必须使用关键字new

总结:
Angular 有些constructor是简写的方式,并没有主体内容,理解背后的原理至关重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值