公共、私有与受保护的修饰符
默认为 public
在上面的例子里,我们可以自由的访问程序里定义的成员。 如果你对其它语言中的类比较了解,就会注意到我们在之前的代码里并没有使用 public
来做修饰;例如,C# 要求必须明确地使用 public
指定成员是可见的。 在 TypeScript 里,成员都默认为 public
,当然你也可以明确的将一个成员标记成 public
。
当成员被标记成 private
时,它就不能在声明它的类的外部访问。
/*
访问修饰符: 用来描述类内部的属性/方法的可访问性
public: 默认值, 公开的外部也可以访问
protected: 类内部、子类可以访问
private: 只有类内部可以访问
*/
//定义Person基类
class Person {
//声明属性
private name:string //name属性加了private修饰,只能在类内部访问
age:number //age属性没有加修饰,默认为public修饰
//构造方法
constructor(name:string,age:number){
this.name = name
this.age = age
}
//一般方法
speak():string{
return `我的名字是${this.name},我的年龄是${this.age}`
}
}
let tom = new Person('tom',19)
//console.log(tom.name) //属性“name”为私有属性,只能在类“Person”中访问
console.log(tom.age) //19
理解 protected
class Person {
private name:string
age:string
constructor (name,age){
this.name = name
this.age = age
}
protected speak():string{
return `我的名字是${this.name},我的年龄是${this.age}`
}
}
class Student extends Person {
sex:string
constructor (name,age,sex){
super(name,age)
this.sex = sex
}
study(){
super.speak() //子类可以访问speak方法
console.log('我在很努力的学习');
}
}
let p1 = new Person('tom',19)
console.log(p1.name); // private私有的-不可见,实例化对象页不可见
console.log(p1.age); // public公开的-可见
console.log(p1.speak());// protected受保护的-不可见
const s = new Student('ls', 20, '男')
console.log(s.name) //不可访问
console.log(s.age)
readonly 修饰符
你可以使用 readonly
class Person {
public readonly name: string = 'abc'
constructor(name: string) {
this.name = name
}
}
let john = new Person('John')
// john.name = 'peter' // error
参数属性
在上面的例子中,我们必须在 Person
类里定义一个只读成员 name
和一个参数为 name
的构造函数,并且立刻将 name
的值赋给 this.name
,这种情况经常会遇到。 参数属性可以方便地让我们在一个地方定义并初始化一个成员。 下面的例子是对之前 Person
类的修改版,使用了参数属性:
class Person2 {
constructor(readonly name: string) {
this.name = name
}
}
const p = new Person2('jack')
console.log(p.name)
注意看我们是如何舍弃参数 name
,仅在构造函数里使用 readonly name: string
参数来创建和初始化 name
成员。 我们把声明和赋值合并至一处。
参数属性通过给构造函数参数前面添加一个访问限定符来声明。使用 private
限定一个参数属性会声明并初始化一个私有成员;对于 public
和 protected
来说也是一样。
存取器
TypeScript
支持通过 getters/setters
来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。
class Person {
protected firstName: string = 'A'
protected lastName: string = 'B'
constructor(firstName,lastName){
this.firstName = firstName
this.lastName = lastName
}
get fullName(){
return this.firstName + '-' + this.lastName
}
set fullName(value){
const names = value.split('-')
this.firstName = names[0]
this.lastName = names[1]
}
}
const p = new Person('zahng','san')
console.log(p.fullName);
p.fullName='a-b'
静态属性
到目前为止,我们只讨论了类的实例成员,那些仅当类被实例化的时候才会被初始化的属性。 我们也可以创建类的静态成员,这些属性存在于类本身上面而不是类的实例上。
class Person {
name: string = 'petter'
static info: string = 'some info'
}
console.log(Person.info)
console.log(new Person().name)
抽象类
抽象类做为其它派生类的基类使用。 它们不能被实例化。不同于接口,抽象类可以包含成员的实现细节。 abstract
关键字是用于定义抽象类和在抽象类内部定义抽象方法。
// 抽象类不是为了实例化对象的.是为了给其他类做模板的
// 让其他类继承抽象类,抽象类就可以当做模板使用了
//定义一个抽象类
abstract class Animal {
abstract name: string
abstract cry ():void //定义一个抽象方法cry
run () { //定义一个方法run
console.log('正在奔跑....')
}
}
class Dog extends Animal {
name: string
cry () {
console.log('汪汪汪!')
}
}
const dog = new Dog()
dog.cry()
dog.run()
4. 函数
TypeScript 为 JavaScript 函数添加了额外的功能,让我们可以更容易地使用。
和 JavaScript 一样,TypeScript 函数可以创建有名字的函数和匿名函数。你可以随意选择适合应用程序的方式,不论是定义一系列 API 函数还是只使用一次的函数。
通过下面的例子可以迅速回想起这两种 JavaScript 中的函数:
// 声明函数
function add(x, y) {
return x + y
}
// 函数表达式
let myAdd = function(x, y) {
return x + y;
}
函数类型
为参数定义类型
让我们为上面那个函数添加类型:
function add(x: number, y: number): number {
return x + y
}
let myAdd = function(x: number, y: number): number {
return x + y
}
我们可以给每个参数添加类型之后再为函数本身添加返回值类型。TypeScript 能够根据返回语句自动推断出返回值类型。
书写完整函数类型
现在我们已经为函数指定了类型,下面让我们写出函数的完整类型。
let myAdd:(x:number,y:number)=>number = function(x:number ,y:number):number{
return x + y
}
可选参数和默认参数
TypeScript 里的每个函数参数都是必须的。 这不是指不能传递 null
或 undefined
作为参数,而是说编译器检查用户是否为每个参数都传入了值。编译器还会假设只有这些参数会被传递进函数。 简短地说,传递给一个函数的参数个数必须与函数期望的参数个数一致。
JavaScript 里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是 undefined
。 在TypeScript 里我们可以在参数名旁使用 ?
实现可选参数的功能。 比如,我们想让 lastName
是可选的:
在 TypeScript 里,我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是 undefined
时。 它们叫做有默认初始化值的参数。 让我们修改上例,把firstName
的默认值设置为 "A"
。
function buildName(firstName: string='A', lastName?: string): string {
if (lastName) {
return firstName + '-' + lastName
} else {
return firstName
}
}
console.log(buildName('C', 'D'))
console.log(buildName('C'))
console.log(buildName())
剩余参数
必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在 JavaScript 里,你可以使用 arguments
来访问所有传入的参数。
在 TypeScript 里,你可以把所有参数收集到一个变量里: 剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号( ...
)后面给定的名字,你可以在函数体内使用这个数组。
function info(x: string,
函数重载
函数重载: 函数名相同, 而形参不同的多个函数 在JS中, 由于弱类型的特点和形参与实参可以不匹配, 是没有函数重载这一说的 但在TS中, 与其它面向对象的语言(如Java)就存在此语法
// 重载函数声明
function add (x: string, y: string): string
function add (x: number, y: number): number
// 定义函数实现
function add(x: string | number, y: string | number): string | number {
// 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 x + y
if (typeof x === 'string' && typeof y === 'string') {
return x + y
} else if (typeof x === 'number' && typeof y === 'number') {
return x + y
}
}
console.log(add(1, 2))
console.log(add('a', 'b'))
// console.log(add(1, 'a')) // error