TypeScript学习笔记(二)函数和类【面向对象】
目录
一、函数的语法
1. 函数声明
在 ES5
中函数的写法:
function run() {
console.log("run");
}
var run2= function() {
console.log("run2");
}
而TypeScript
中主要的不同点是函数需要标明参数的类型和返回值类型。
函数声明方式:
function 函数名(参数类型 参数名): 返回值类型 {
return 值;
}
匿名函数:
let 变量值 = function(参数类型 参数名): 返回值类型 {
return 值;
}
例如:
function getInfo(name:string, age: number): string {
return `${name}---${age}`
}
let getInfo2 = function(name:string, age: number): string {
return `${name}---${age}`
}
2. 函数的可选参数
语法:在选填的参数后添加 ?
即可:
function getInfo(name:string, age?: number): string {
if(age) {
return `${name}---${age}`
}
else {
return `${name}---年龄保密`
}
}
当调用:
getInfo("mike")
运行结果:
而当填入第二个参数时:
console.log(getInfo("mike", 15))
运行结果:
tips: 可选参数必须配置在参数列表的
最后面
。
3. 函数的默认参数
function getInfo(name:string, age: number=20): string {
return `${name}---${age}`
}
console.log(getInfo("mike"))
运行结果:
4. 函数的剩余参数
类似其他语言的可变参数:
function sum(...result: number[]):number {
return result.reduce((preValue, item)=>preValue+item)
}
console.log("sum", sum(1,2,3,4));
运行结果:
此外我们还可以取前面几个参数,然后后面的参数被分配到剩余参数中:
function sum(a: number, b: number,...result: number[]):number {
console.log("first two number: ", a, b);
return result.reduce((preValue, item)=>preValue+item)
}
console.log("sum", sum(1,2,3,4));
运行结果:
5. 函数的重载
function fun(name: string): string;
function fun(age: number): string;
function fun(val: any): any {
if(typeof str === 'string'){
return 'string类型:'+val;
}
else {
return '我的年龄是:'+val;
}
}
调用:
console.log(fun("Hello world"));
console.log(fun(18));
运行结果;
二、JavaScript中的类(ES5)
1. 在构造函数中定义成员变量和方法
function Person() {
this.name = '张三';
this.age = 15;
}
使用 new
关键字创建一个对象并打印:
var person = new Person();
console.log(person);
添加成员方法:
function Person() {
this.name = '张三';
this.age = 15;
this.run = function() {
console.log(this.name + '在奔跑');
}
}
调用:
person.run();
2. 在原型链中定义变量和方法
Person.prototype.sex = "男";
Person.prototype.work = function() {
console.log(this.name + "在工作");
}
var p = new Person();
p.work();
运行结果:
原型链上面的属性会被多个实例共享,而构造函数中的不会。
3. 静态方法
Person.getInfo = function() {
console.log("我是静态方法")
}
调用方式:
Person.getInfo();
4. 类的继承
使用原型链+对象冒充
的组合继承模式
- 对象冒充方式:
function Student() {
Person.call(this);// 对象冒充实现继承,可以继承构造函数中定义的成员
}
let student = new Student();
student.run();
但这样无法继承原型链中定义的属性和方法。
- 原型链方式:
function Student() {
}
Student.prototype = new Person();
let student = new Student();
student.work();// 调用原型链中添加的方法
这种方式既可以继承构造函数中定义的成员,也可以继承原型链中定义的成员。
存在的问题:实例化子类的时候没法给父类传参。
- 组合继承模式:
function Student(name, age) {
Person.call(this, name, age); // 1.对象冒充
}
Student.prototype = new Person(); // 2.原型链
let student = new Student("李四", 18);
student.work();// 调用原型链中添加的方法
三、 TypeScript中的类
1. 类的定义
class Person {
name: string; // 属性
constructor(n:string) {
this.name = n;
}
run(): void {
console.log(this.name + "在奔跑");
}
}
var person = new Person("张三");
person.run();
可以看到,类的定义和 Java
、C++
等语言基本相同,非常人性化。
2. 类的方法
class Person {
...
getName():string {
return this.name;
}
setName(name:string):void {
this.name = name;
}
}
3. 继承的实现
使用 extends
关键字:
class Student extends Person {
constructor(name:string) {
super(name);
}
}
var student = new Student("李四");
student.run();
不得不说,这才是真正的 ”Java“Script吧?和 Java
代码相似度99%。
方法的重写(即Java中的Override):
class Student extends Person {
constructor(name:string) {
super(name);
}
// 重写的方法
run(): void {
console.log(this.name + "在奔跑(学生)");
}
}
var student = new Student("李四");
student.run();
4. 类中的修饰符
public
protected
private
作用与 C++
和 Java
等中的作用一致。
tips:属性如果不添加修饰符,默认是
public
5. 静态属性和静态方法
class Person {
// ...
// 静态属性
protected static personNum:number = 0;
constructor(n:string) {
this.name = n;
Person.personNum++;
}
// ...
// 静态方法
static printPersonNum():void {
console.log(Person.personNum);
}
}
示例:
var p1 = new Person("张三");
var p2 = new Person("李四");
var p3 = new Person("王五");
Person.printPersonNum();
6. 抽象类的定义
语法:
abstract class 类名{
abstract 抽象方法名(): 返回值类型 {
...
}
...
}
7. 接口的定义
属性接口
语法
interface 接口名 {
接口中包含的属性...
}
示例:
// 属性接口
interface FullName {
firstName: string;
lastName: string;
}
// 使用
function printName(fullName: FullName) {
console.log(`${fullName.firstName}--${fullName.lastName}`);
}
let obj = {
age: 15,
firstName: "mike",
lastName: "smith"
}
printName(obj);
即约束了传入的对象必须包含接口所规定的参数。
运行结果:
接口的可选属性
语法和可选参数相同,既是在变量名后面加上 ?
:
interface FullName {
firstName: string;
lastName?: string;
}
使用接口语法模拟封装ajax请求的参数对象:
interface Config {
type: string;
url: string;
data?: string;
dataType: string;
}
function ajax(config: Config) {
var xhr = new XMLHttpRequest();
xhr.open(config.type, config.url, true);
xhr.send(config.data);
xhr.onreadystatechange = ()=>{
if(xhr.readyState==4 && xhr.status == 200){
console.log("成功");
}
}
}
可见使用接口可以很方便地使IDE
为我们提供输入参数的类型提示,与 JavaScript
中需要翻看文档形成鲜明的对比。
函数类型接口
interface encrypt {
(key:string, val:string) : string;
}
var md5:encrypt = function(key:string, value:string) {
return "使用md5加密后的字符串";
}
var sha1:encrypt = function(key:string, value:string) {
return "使用sha1加密后的字符串";
}
可索引接口
对数组的约束
interface nameArr {
[index: number]:string
}
let nameList: nameArr = ["mike","Jack","Sam"];
对对象的约束
interface strMap {
[index: string]:string;
}
var map:strMap = {
"mike": "123@qq.com",
"Jack": "456@qq.com"
}
类类型接口
和 Java
的接口比较类似,TypeScript
的接口多了属性约束,并使用 implements
关键字来实现接口:
interface Animal {
name: string;
eat(food:string):void;
}
class Dog implements Animal {
name: string;
constructor(name:string) {
this.name = name;
}
eat(food: string): void {
console.log(`小狗${this.name}吃${food}`)
}
}
8. 接口的继承
interface Workable extends Animal {
work():void;
}