我们声明一个 Greeter类。这个类有3个成员:一个叫做greeting的属性,一个构造函数和一个greet方法。

We declare a Greeter class. This class has three members: an attribute called greeting, a constructor, and a green method

我们在引用任何一个类成员的时候都用了this。它表示我们访问的是类的成员。

We use this when we refer to any class member. It means that we are visiting members of the class.

最后一行,我们使用new构造了Greeter类的一个实例。它会调用之前定义的构造函数,创建一个 Greeter类型的新对象,并执行构造函数初始化它。

In the last line, we use new to construct an instance of the Greeter class. It calls the previously defined constructor,

creates a new object of Greeter type, and executes the constructor to initialize it.

class Greeter{
greeting:string;
constructor(message:string){
this.greeting=message
}
greet(){
return "hello"+this.greeting;
}
}
let greeter=new Greeter("world");

继承

inherit

在TypeScript里,我们可以使用常用的面向对象模式。当然,基于类的程序设计中最基本的模式是允许使用继承来扩展现有的类。

In TypeScript, we can use commonly used object-oriented patterns. Of course, the most basic

pattern in class-based programming is to allow inheritance to extend existing classes.

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类和Horse类都创建了move方法,它们重写了从Animal继承来的move方法,

使得move方法根据不同的类而具有不同的功能。 注意,即使 tom被声明为Animal类型,

但因为它的值是Horse,tom.move(34)会调用Horse里的重写方法:

The example above demonstrates how to override a parent class in a subclass. Both Snake and Horse classes create motion methods,

which override the motion methods inherited from Animal.It makes the move method have different functions according to

different classes. Notice that even if Tom is declared as an Animal type,But because its value is Horse,

tom. move (34) calls the rewrite method in Horse:

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

Public, Private and Protected Modifiers

默认为public

Default to public

我们可以用下面的方式来重写上面的 Animal类:

We can override the Animer class above in the following way:

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

理解private

Understand private

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

When a member is marked private, it cannot be accessed externally by declaring its class. For example:

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

TypeScript使用的是结构性类型系统。 当我们比较两种不同的类型时,并不在乎它们从何处而来,

如果所有成员的类型都是兼容的,我们就认为它们的类型是兼容的。

TypeScript uses a structured type system. When we compare two different types, we don't care where they come from.

If all members'types are compatible, we think their types are compatible.

然而,当我们比较带有private或protected成员的类型的时候,情况就不同了。 如果其中一个类型里包含一个 private成员,

那么只有当另外一个类型中也存在这样一个private成员, 并且它们都是来自同一处声明时,我们才认为这两个类型是兼容的。

对于 protected成员也使用这个规则。

However, when we compare types with private or protected members, the situation is different. If one of

the types contains a private member,Then only when there is such a private member in another type, and

they all come from the same declaration, do we think the two types are compatible.This rule is also used for protected members.

class Animal{
private name:string;
constructor(theName:string){this.name=theName}
}
class Bob extends Animal{
constructor(){super("Bob");}
}
class Employee{
private name:string;
constructor(theName:string){this.name=theName}
}
let animal= new Animal("Goat");
let bob=new Bob();
let employee=new Employee("Bob");
animal=bob;
animal=employee;//Animal and Employee are not compatible

因为 Animal和Rhino共享了来自Animal里的私有成员定义private name: string,因此它们是兼容的。

Because Animal and Rhino share private member definition private name: string from Animal, they are compatible.

然而 Employee却不是这样。当把Employee赋值给Animal的时候,得到一个错误,说它们的类型不兼容。

Employee, however, is not. When Employee is assigned to Animal, an error is made stating that their types are incompatible.

尽管 Employee里也有一个私有成员name,但它明显不是Animal里面定义的那个。

Although Employee also has a private member name, it is clearly not the one defined in Animal.

理解protected

Understanding protected

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

Protected modifiers behave very similar to private modifiers, but one difference is that protected members

are still accessible in derived classes. For example:

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 Employee("Howard","Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name);//error

注意,我们不能在Person类外使用name,但是我们仍然可以通过Employee类的实例方法访问,

因为Employee是由Person派生而来的。

Note that we can't use name outside the Person class, but we can still access it through the instance

method of the Employee class, because Employee is derived from Person.

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

Constructors can also be marked protected. This means that the class cannot be instantiated outside

the class that contains it, but can be inherited. For example,

class Person{
protected name:string;
protected constructor(theName:string){this.name=theName;}
}
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");

readonly修饰符

readonly Modifier

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

You can use the readonly keyword to set the properties to read-only. Read-only

properties must be initialized at declaration time or in constructors.

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-picec suit";// error! name is readonly.

参数属性可以方便地让我们在一个地方定义并初始化一个成员。 下面的例子是对之前 Animal类的修改版,使用了参数属性:

Parameter attributes make it easy for us to define and initialize a member in one place. The following example is a

modified version of the previous Animal class, using parameter attributes:

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

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

Notice how we abandoned the Name and only used the private name: string parameter in the constructor to create and initialize name

members. We merge declarations and assignments in one place.

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

The parameter attribute is declared by adding an access qualifier to the constructor parameter. Using private to qualify a parameter attribute

declares and in

itializes a private member; the same is true for public and protected

存取器

Accessor

TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

TypeScript Support for intercepting access to object members through getters/setters. It can help you

effectively control access to the members of the object.

下面来看如何把一个简单的类改写成使用get和set。 首先,我们从一个没有使用存取器的例子开始。

Let's see how to rewrite a simple class to use get and set. First, let's start with an example of not using an accessor.

class Employee{
fullName:string;
}
let employee=new Employee();
employee.fullName="Bob Smith";
if(employee.fullName){
console.log(employee.fullName);
}

下面这个版本里,我们先检查用户密码是否正确,然后再允许其修改员工信息。 我们把对 fullName的直接访问改成了可以检查密码的set方法。

我们也加了一个 get方法,让上面的例子仍然可以工作。

In the following version, we first check whether the user's password is correct, and then allow it to modify employee information.

We changed direct access to fullName to a set method that checks passwords. We also added a get method to make the above example work.

let passcode="secret passcode";
class Employee{
private _fullName:string;
get fullName():string{
return this._fullName;
}
set fullName(newName:string){
if(passcode&&passcode=="secret passcode"){
this._fullName=newName;
}else{
console.log("Error:Unauthorized update of employee");
}
}
}
let employee=new Employee();
employee.fullName="Bob Smith";
if(employee.fullName){
alert(employee.fullName);
}

我们可以修改一下密码,来验证一下存取器是否是工作的。当密码不对时,会提示我们没有权限去修改员工。

We can modify the password to verify that the accessor works. When the password is incorrect,

we will be prompted that we do not have permission to modify employees.

对于存取器有下面几点需要注意的:

For accessors, there are the following points to note:

首先,存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。

其次,只带有 get不带有set的存取器自动被推断为readonly。 这在从代码生成 .d.ts文件时是有帮助的,

因为利用这个属性的用户会看到不允许够改变它的值。

First, the accessor requires you to set the compiler to output ECMAScript 5 or higher. Degradation to ECMAScript 3

is not supported. Secondly, an access with only get and without set is automatically inferred as readonly. This is helpful

when generating. D. TS files from code, because users using this property will see that it is not allowed to change its value.

静态属性

Static attribute

我们使用 static定义origin,因为它是所有网格都会用到的属性。 每个实例想要访问这个属性的时候,都要在 origin前面加上类名。

如同在实例属性上使用 this.前缀来访问属性一样,这里我们使用Grid.来访问静态属性。

We use static to define origin, because it is an attribute that all grids will use. When each instance wants to access this property,

it must precede the origin with the class name. Just as we use this. prefix to access attributes on instance attributes,

we use Grid. to access static attributes.

class Grid{
static origin={x:0,y:0};
calculateDistanceFromOrigin(point:{x:number;y:number;}){
let xDist=(point.x-Grid.origin.x);
let yDist=(point.y-Grid.origin.y);
return Math.sqrt(xDist*xDist+yDist*yDist)/this.scale;
}
constructor(public scale:number){}
}
let grid1=new Grid(1.0);
let grid2=new Grid(5.0);
console.log(grid1.calculateDistanceFromOrigin({x:10,y:10}));
console.log(grid2.calculateDistanceFromOrigin({x:10,y:10}));

抽象类

abstract class

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,

Abstract classes are used as base classes for other derived classes. They are generally not instantiated directly. Unlike interfaces,

抽象类可以包含成员的实现细节。abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。

Abstract classes can contain implementation details of members. Abstract keywords are used to define

abstract classes and to define abstract methods within Abstract classes.

abstract class Animal{
abstract makeSound():void;
move():void{
console.log("roaming the earch...");
}
}

抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。

然而,抽象方法必须包含 abstract关键字并且可以包含访问修饰符。

Abstract methods in abstract classes do not contain concrete implementations and must be implemented in derived classes.

The syntax of abstract methods is similar to that of interface methods. Both define method signatures but do not contain

method bodies. However, abstract methods must contain Abstract keywords and can contain access modifiers.

abstract class Department{
constructor(public name:string){}
printName():void{
console.log('Department name'+this.name);
}
abstract printMeeting():void;//必须在派生类中实现 Must be implemented in a derived class
}
class AccountingDepartment extends Department{
constructor(){
super("Account and Auditing");
}
printMeeting():void{
console.log('The Accounting Department meets each Monday at 10am.')
}
generateReports():void{
console.log('Generating accounting reports...');
}
}
let department: Department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type

高级技巧Advanced Skills

当你在TypeScript里声明了一个类的时候,实际上同时声明了很多东西。 首先就是类的 实例的类型。

When you declare a class in TypeScript, you actually declare a lot of things at the same time. The first is the type of instance of the class.

class Greeter{
greeting:string;
constructor(message:string){
this.greeting=message;
}
greet(){
return "Hello"+this.greeting;
}
}
let greeter:Greeter;
greeter=new Greeter("world");
console.log(greeter.greet());

我们写了let greeter: Greeter,意思是Greeter类的实例的类型是Greeter。 我们也创建了一个叫做构造函数的值。

这个函数会在我们使用 new创建类实例的时候被调用.

We wrote let greeter: Greeter, meaning that the type of instance of the Greeter class is Greeter.

We also created a value called a constructor. This function will be called when we use new to create class instances.

让我们稍微改写一下这个例子,看看它们之前的区别:

Let's rewrite this example a little and see the difference between them before:

class Greeter{
static standardGreeting="Hello,there";
greeting:string;
greet(){
if(this.greeting){
return "Hello"+this.greeting;
}else{
return Greeter.standardGreeting;
}
}
}
let greeter1:Greeter;
greeter1=new Greeter();
console.log(greeter1.greet());
let greeterMarker:typeof Greeter=Greeter;
greeterMarker.standardGreeting="Hey there";
let greeter2:Greeter=new greeterMarker();
console.log(greeter2.greet());

我们创建了一个叫做 greeterMaker的变量。这个变量保存了这个类或者说保存了类构造函数。然后我们使用 typeof Greeter,

意思是取招待员类的类型,而不是实例的类型。或者更确切的说, “我告诉 Greeter标识符的类型”,也就是构造函数的类型。

这个类型包含了类的所有静态成员和构造函数。之后,就和前面一样,在我们 greeterMaker上使用new,创建³³ Greeter的实例。

We created a variable called greeterMaker. This variable holds the class or class constructor. Then we use typeof Greeter,

which means the type of the receptionist class, not the type of the instance. Or rather, "I tell Greeter the type of identifier,"

which is the type of constructor. This type contains all the static members and constructors of the class. Then, as before,

we use new on our greeterMaker to create an instance of 172

把类当做接口使用

Use classes as interfaces

类定义会创建两个东西:类的实例类型和一个构造函数。因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。

Class definitions create two things: the instance type of the class and a constructor. Because classes

can create types, you can use classes where interfaces are allowed.

class Point{
x:number;
y:number;
}
interface Point3d extends Point{
z:number;
}
let point3d:Point3d={x:1,y:2,x:3};

typescript类(学习笔记非干货)的更多相关文章

  1. typescript泛型(学习笔记非干货)

    软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性. 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型, 这在创建大型系统时为你提供了十分灵活的功能. In softwa ...

  2. typescript接口(学习笔记非干货)

    typescript的核心原则之一就是对所具有的shape类型检查结构性子类型化 One of the core principles of typescript is to check struct ...

  3. typescript基础类型(学习笔记非干货)

    布尔值 Boolean let isDone:boolean=false; 数字 Number let decLiteral:number=6; let hexLiteral:number=0xf00 ...

  4. typescript枚举,类型推论,类型兼容性,高级类型,Symbols(学习笔记非干货)

    枚举部分 Enumeration part 使用枚举我们可以定义一些有名字的数字常量. 枚举通过 enum关键字来定义. Using enumerations, we can define some ...

  5. typescript变量声明(学习笔记非干货)

    var a=10; function f(){ var message="hello,world"; return message; } function f(){ a=10; r ...

  6. mongoDB 学习笔记纯干货(mongoose、增删改查、聚合、索引、连接、备份与恢复、监控等等)

    最后更新时间:2017-07-13 11:10:49 原始文章链接:http://www.lovebxm.com/2017/07/13/mongodb_primer/ MongoDB - 简介 官网: ...

  7. typescript handbook 学习笔记4

    概述 这是我学习typescript的笔记.写这个笔记的原因主要有2个,一个是熟悉相关的写法:另一个是理清其中一些晦涩的东西.供以后开发时参考,相信对其他人也有用. 学习typescript建议直接看 ...

  8. typescript handbook 学习笔记3

    概述 这是我学习typescript的笔记.写这个笔记的原因主要有2个,一个是熟悉相关的写法:另一个是理清其中一些晦涩的东西.供以后开发时参考,相信对其他人也有用. 学习typescript建议直接看 ...

  9. System类学习笔记

    最近在学习源码的过程中发现:很多深层次的代码都用到了一个类System类,所以决定对System类一探究竟 本文先对System类进行了剖析,然后对System类做了总结 一.首先对该类的中的所有字段 ...

随机推荐

  1. vim命令记录

    最近开始用vim作为日常编辑器,由于vim的命令过多,现在记录一下

  2. ProxySQL实现Mysql读写分离 - 部署手册

    ProxySQL是一个高性能的MySQL中间件,拥有强大的规则引擎.ProxySQL是用C++语言开发的,也是percona推的一款中间件,虽然也是一个轻量级产品,但性能很好(据测试,能处理千亿级的数 ...

  3. Linux下的计算命令和求和、求平均值、求最值命令梳理

    在Linux系统下,经常会有一些计算需求,那么下面就简单梳理下几个常用到的计算命令 (1)bc命令bc命令是一种支持任意精度的交互执行的计算器语言.bash内置了对整数四则运算的支持,但是并不支持浮点 ...

  4. oracle ocp视频教程笔记

    show parameter user user_dump_dest  string  /u01/app/oracle/diag/rdbms/orcl/orcl/trace oracle日志存放位置d ...

  5. Java多线程的使用以及原理

    Java有两种方式实现多线程. 第一种——继承Thread类,并重写run方法 步骤: 定义类继承Thread类: 重写子类的run方法,将线程需要执行的代码写在run方法中: 创建子类的对象,则创建 ...

  6. Linux内核分析第三周学习总结

    Linux内核源码简介 arch/ 该目录中包含和硬件体系结构相关的代码,每种平台占一个相应的目录. 和32位PC相关的代码存放在x86目录下. 每种平台至少包含3个子目录:kernel(存放支持体系 ...

  7. javaBean中 字符串 转 date 类型转换

    1-----创建javabean 代码如下 package BeanUtils; import java.util.Date; public class Admin { private String ...

  8. 安装python包时报错

    pip install numpy  时  报错: Traceback (most recent call last):  File "d:\学习\python\python-3.6.5\l ...

  9. 【Deep Hash】NINH

    [CVPR 2015] Simultaneous Feature Learning and Hash Coding with Deep Neural Networks [paper] Hanjiang ...

  10. HDOJ1287_破译密码

    一道正常简单题 曲折解题 做这题的时候看了很久没有看懂是什么意思,最后以为是一道单独的数学题把B这个大写字母猜出来进行异或运算,还不知道C里面异或运算可以直接有符号的:),导致又去学习了一下十进制转换 ...