我们声明一个 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. 后台跑包方法 断开ssh程序也能继续执行的方法screen命令

    aircrack-ng -w 字典路径 握手包路径 screen -S 001创建会话 screen -ls  列出窗口列表 screen -r 5位数字  进入会话指令 如果会话恢复不了,则是有可能 ...

  2. 回溯法解n皇后问题

    #include<bits/stdc++.h> using namespace std; int n,sum; int c[100]; void search(int cur){ if(c ...

  3. sixsix团队M2阶段Postmortem

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 要解决的问题:目前外卖网站比较多,用户很难快速找到合适的外卖,我们集合各个网站的外卖信息,为用户提 ...

  4. java-过滤器、拦截器

    1.基础知识 1.1面向对象编程(OOP).面向切面编程(AOP) 面向对象编程: 将需求功能划分为不同的.相对独立的和封装良好的类,使他们有属于自己的行为,依靠继承和多态等来定义彼此的关系. 面向切 ...

  5. centos7编译安装zabbix(附带编译安装lnmp)

    先把防火墙和selinux关闭: sytemctl stop firewalld setenforce 0 1.yum安装依赖: yum -y install wget openssl* gcc gc ...

  6. Neo4j学习案例【转】

    转自 打怪的蚂蚁 CSDN: https://blog.csdn.net/xgjianstart/article/details/77285334 neo4j有社区版本和企业版.社区版本是免费的,只支 ...

  7. wordpress升级出错

    服务器是腾讯云 搜索到的解决方案有几个,试了好几个,不知道哪个是根本原因,反正都操作了. 设置wordpress文件夹和子文件夹的权限 编辑wp-config.php,在文末添加如下: define( ...

  8. [BUAA_SE_2017]案例分析-Week3

    Week3 案例分析 一.调研评测 案例: 神策数据的数据概览功能 Demo: 电商类产品Demo 评价: d) 好,不错 个人评价:神策数据电商类产品Demo的数据概览功能是相当不错的.首先点击进入 ...

  9. Minify or format javascript file by web or notepad++

    Notepad++ plugin manager install 'JSTOOL' http://tool.oschina.net/codeformat/js https://www.cnblogs. ...

  10. Delphi/XE2 使用TIdHttp控件下载Https协议服务器文件[转]

    之前的一篇博文详细描述了使用TIdhttp控件下载http协议的文件,在我项目的使用过程中发现对于下载Https协议中的文件与Http协议的文件不同,毕竟Https在HTTP协议基础上增加了SSL协议 ...