TypeScript
是什么
可以编译成JavaScript。添加了类型系统的JavaScript;「类型」是其最核心的特性
JavaScript 的灵活 使得它的代码质量参差不齐,维护成本高,运行时错误多。
TypeScript 的类型系统,在很大程度上限制了 JavaScript 的灵活
TypeScript 是静态类型
JavaScript 是解释类型 动态的
TypeScript 是弱类型
这段代码不管是在 JavaScript 中还是在 TypeScript 中都是可以正常运行的,运行时数字 1 会被隐
式类型转换为字符串 '1' ,加号 + 被识别为字符串拼接,所以打印出结果是字符串 '11' 。
console.log(1 + '1');
// 打印出字符串 '11'
怎么用
环境准备&命令使用
# 安装并编译TypeScript
t需要nodejs环境,如果电脑没有npm命令的,可以去官网下载并安装nodejs
https://nodejs.org/en
# TypeScript安装命令
npm install -g typescript
# 查看版本号
tsc --version
# 将ts编译为js
新建一个文件index.ts
然后在当前目录下输入命令:tsc index.ts
指定目录进行输出:tsc --outFile ./js/index.js index.ts
持续输出按保存即可编译:tsc --watch --outFile ./js/index.js ./ts/index.ts
语法学习
ts文件
引入ts文件
// 数字类型
let count:number = 12;
// Boolean
const isDone:boolean = false;
const isDone1:Boolean = false;
// string
let hell:string = `你好,我叫张三,今年${count}岁了`
let hell1:string = `hellow,my name is zhangsan, age is ${count}`
//可以用 void 表示没有任何返回值的函数
function f():void {
console.log("voidFun")
}
//声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null
let voidName:void = null;
let voidName1:void = undefined;
// 任意值(Any)用来表示允许赋值为任意类型。 相当于使用了JavaScript的语法,跟没有使用ts一样
let anyTypeVar:any = "8"
console.log(anyTypeVar)
anyTypeVar = 9
console.log(anyTypeVar)
anyTypeVar = false
console.log(anyTypeVar)
//any 类型的 可以任意使用属性和方法
console.log(anyTypeVar.hahaha);
console.log(anyTypeVar.hahaha.aaaaaa);
console.log(anyTypeVar.fun());
// any 结论:声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
//类型推论
/*
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类
型。
----也就是
1,第一次如果声明同时进行了赋值,那么推出对应的类型;
2.如果只声明则就是any类型
*/
let mytestVar = "seven";
// mytestVar = 7;
let mytestVar1;
mytestVar1 = 7;
mytestVar1 = "89898";
/*
联合类型(Union Types)表示取值可以为多种类型中的一种。
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型
里共有的属性或方法:
1. 就近原则 ---》最近一次的赋值 然后推断类型
*/
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// function getLength(something: string | number): number {
// return something.length;
// }
function getString(something: string | number): string {
return something.toString();
}
/*
ts中如何定义一个接口?
在 TypeScript 中,我们使用Interfaces来定义一个接口。 相当于一个自定义数据类型(暂且可以这么理解)
它是对行为的抽象,而具体如何行动需要由类去实现。
1. 定义了接口在实例化的时候必须将所有属性赋值,如果没有则报错 |定义的变量与接口的属性数量、内容不一致是不允许的:
结论:赋值的时候,变量的和接口的保持一致。
2. 赋值用英文冒号 “:” 不要使用=
*/
interface person {
name:String,
age:Number,
address:String
}
// let tom:person;
let tom1:person={
name:"zhagnsna",
age:89,
address:"hahaha"
}
//如果不想完全匹配接口属性怎么办? 可以用可选属性:
/*
定义属性的时候加个问号即可
例如:width?:Number
*/
interface ant {
size:String,
width?:Number// 可选属性
}
let jerry:ant;
jerry = {
width:8989,
size:"haahha"
}
let jerry1:ant={
size:"9999999"
}
//任意属性,在接口中添加任意的属性
interface Person {
name: string;
age?: number;
[propName: string]: any; // 定义了任意类型的任意属性
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
//只读属性 readonly name: string;
/*
readonly 添加在变量名称前面
*/
interface Person1 {
readonly name: string;
age?: number;
[propName: string]: any; // 定义了任意类型的任意属性
}
let tom222: Person1 = {
name: 'Tom',
gender: 'male'
};
// tom222.name = "ssss"
/*
数组 最简单的方法是使用「类型 + 方括号」来表示数组:
也可以指定一个any类型的数组:
*/
let arr:number[] = [1,2,3,4,5,65]
console.log(arr)
arr.push(999)
console.log(arr)
// arr.push("sss")
// let arr2:number[] = ['1',2,3,4,5,65]
let list: any[] = ['xcatliu', 25, { website: 'http://xcatliu.com' }];
/*
函数声明
*/
// 函数声明(Function Declaration)
function sum(x, y) {
return x + y;
}
//,输入多余的(或者少于要求的)参数,是不被允许的:
function sum1(x: number, y: number): number {
return x + y;
}
sum1(8,9)
// sum1(8,9,111)
/*
函数表达式
*/
// 函数表达式(Function Expression)
let mySum = function (x, y) {
return x + y;
};
// 自动推断类型
let mySum2 = function (x: number, y: number): number {
return x + y;
};
//手动设置类型
/*
(x: number, y: number) => number
这里的箭头是ts中的箭头 用来表示函数的定义 左边是输入类型,需要用括号括起来,右边是输出类型。
在 ES6 中, => 叫做箭头函数
*/
let mySum3: (x: number, y: number) => number = function (x: number, y: number):
number {
return x + y;
};
/*
用接口定义函数
类型设置
变量名:类型--->用括号括起来 然后 : 类型
*/
interface funObj {
(input1:String,input2:String):String
}
let myFun:funObj;
myFun("aaa","bbb");
let myFun1:funObj;
/*
优势:采用函数表达式|接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证
参数个数、参数类型、返回值类型不变。
*/
let myfun2 = function (input1:String,input2:String) {
return input1.toUpperCase()+input2.toUpperCase()
}
//函数 可选参数
/*
用 ? 表示可选的参数:
1.可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必需参数了:
*/
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat10 = buildName('Tom', 'Cat');
let tom10 = buildName('Tom');
/*
参数默认值
此时就不受「可选参数必须接在必需参数后面」的限制了:
*/
function buildName1(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat1 = buildName('Tom', 'Cat');
let tom111 = buildName('Tom');
function buildName2(firstName: string = 'Tom', lastName: string) {
return firstName + ' ' + lastName;
}
let tomcat22 = buildName('Tom', 'Cat');
let cat2222 = buildName(undefined, 'Cat');
/*
剩余参数
*/
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
/*
重载
*/
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
/*
断言;在使用联合类型时只能访问公共的属性,如果已经确定要访问的属性,传入的参数无法区分,所以用断言来进行限定类型,去除联合类型的干扰
error as ApiError
值 as 类型
1. 在面对 如果类型时一个接口 的时候,必须使用as 来进行,不能使用instanceof
接口是一个类型,不是一个真正的值,它在编译结果中会被删除,当然就无法使用 instanceof 来做运行时判断了
2.对于 as any
来源:
1.可能是受到 TypeScript 类型系统的限制而无法精确定义类型的场景。
2.历史遗留的或其他人编写的烂代码
3.第三方库未能定义好自己的类型
一方面不能滥用 as any,另一方面也不要完全否定它的作用,我们需要在类型的严格性和开发的
便利性之间掌握平衡(这也是 TypeScript 的设计理念之一),才能发挥出 TypeScript 最大的价值。
联合类型可以被断言为其中一个类型
父类可以被断言为子类
任何类型都可以被断言为 any
any 可以被断言为任何类型
类型断言的限制
类型A中的属性与类型B中的属性必须有重叠,哪怕只有一个;就可以互相断言;
===============
双重断言
是不是可以使用双重断言 as any as Foo 来将任何一个类型断言为任何另一个类型呢?
若使用双重断言,则可以打破「要使得 A 能够被断言为 B ,只需要 A 兼容 B 或 B 兼容 A 即可」的限制,将任何一个类型断言为任何另一个类型。
除非迫不得已,千万别用双重断言。
类型断言语句在编译结果中会被删除;言只会影响 TypeScript 编译时的类型
类型断言不是类型转换,它不会真的影响到变量的类型。
//a断言为b时,a和b有重叠的部分即可
//a声明为b时,a必须具备b的所有属性和方法
类型声明是比类型断言更加严格的。
为了增加代码的质量,我们最好优先使用类型声明,这也比类型断言的 as 语法更加优雅。
*/
/*
any具有优势也有劣势,那么有更优的解决any的方案吗?
答案:添加一个泛型 ;用来规范对类型的限制
*/
function getCacheData(key: string): T {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom33 = getCacheData('tom');
tom.run();
/*
类型别名
类型别名用来给一个类型起个新名字
string 是一个类型
Name 是string 的别名
type 用来声明 Name 是一个类型的别名
类型别名常用于联合类型。
使用 type 定了一个字符串字面量类型 EventNames ,它只能取三种字符串中的一种。
类型别名与字符串字面量类型都是使用 type 进行定义。
*/
type Name = string;
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}
handleEvent(document.getElementById('hello'), 'scroll'); // 没问题
// handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为
// 'dblclick'
/*
元组:数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
用中括号扩住类型 同时用中括号 扩住数据
初始化|赋值的时候必须给所有的类型赋值
添加元素的时候只能添加定义的联合类型的数据,其他类型的数据无法添加
*/
let tomm:[string,number] = ["shagn",999];
console.log(tomm[0])
console.log(tomm[1])
/*
枚举类型
枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:
*/
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
/*
面向对象(OOP)的三大特性:封装、继承、多态
封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要
(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改
对象内部的数据
继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比
如 Cat 和 Dog 都继承自 Animal ,但是分别实现了自己的 eat 方法。此时针对某一个实例,我
们无需了解它是 Cat 还是 Dog ,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行
eat
抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的
抽象方法必须在子类中被实现
接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现
(implements)。一个类只能继承自另一个类,但是可以实现多个接口
使用 class 定义类,使用 constructor 定义构造函数。
通过 new 生成新实例的时候,会自动调用构造函数。
*/
class Animal1{
public _name;
constructor(name:string) {
this._name = name;
}
sayHi1(){
return `My name is ${this._name}`
}
}
let aaaa = new Animal1('wangwang')
console.log(aaaa.sayHi1());
//get set
class Animal111 {
private _name
constructor(name) {
this._name = name;
}
getName() {
return 'Jack';
}
setName(value) {
console.log('setter: ' + value);
}
}
let aaaaa = new Animal111('Kitty'); // setter: Kitty
aaaaa.setName("tom");
// = 'Tom'; // setter: Tom
console.log(aaaaa.getName()); // Jack
/*
静态方法
static修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:
*/
class Anmil1 {
private _age:number;
protected _name1:String;
public _address:string;
constructor(age:number) {
this._age = age;
}
static sayhello(toPerson:String){
return `hello ${toPerson}`
}
}
let ccc = Anmil1.sayhello('张三')
// console.log(ccc._age);
// console.log(ccc._name);
// console.log(ccc._address);
/*
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定
类型的一种特性。
在类型后面使用尖括号包裹
把使用any 的地方换成 T 然后把返回值的类型也改成T【】
*/
function createArray(legth:number,value:T):Array {
let result:T[] = [];
for (let i = 0; i < legth; i++) {
result[i] = value;
}
return result;
}
createArray(8,9)
/*
泛型的多个参数
跟在函数名称后面 入参,出参
使用元祖,返回元组,获取元组的下标
*/
function swap(tuple:[K,V]):[K,V] {
return [tuple[0],tuple[1]];
}
swap(["llll",9999]);
interface lengthwise {
length:number;
}
// T这个泛型不一定拥有length方法,所以使用extends 一个接口,使用对应接口具有的属性和方法
function longginIdentity(arg:T):T {
console.log(arg.length)
return arg;
}
longginIdentity("7");// 不报错
// longginIdentity(7);// 报错Argument of type 'number' is not assignable to parameter of type 'lengthwise'.
/*
泛型接口
*/
interface CreateArrayFunc {
(length: number, value: T): Array;
}
/*
泛型类
*/
class GenericNumber {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
/*
泛型参数的默认类型
*/
function createArra111(length: number, value: T): Array {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
/*
声明合并,同名函数、接口、类的合并
定义的名称相同,获取 并集,编译后出现的并集;但是不好维护,在各个文件中,慎用
*/
js文件
js文件
// 数字类型
var count = 12;
// Boolean
var isDone = false;
var isDone1 = false;
// string
var hell = "\u4F60\u597D\uFF0C\u6211\u53EB\u5F20\u4E09\uFF0C\u4ECA\u5E74".concat(count, "\u5C81\u4E86");
var hell1 = "hellow\uFF0Cmy name is zhangsan, age is ".concat(count);
//可以用 void 表示没有任何返回值的函数
function f() {
console.log("voidFun");
}
//声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null
var voidName = null;
var voidName1 = undefined;
// 任意值(Any)用来表示允许赋值为任意类型。 相当于使用了JavaScript的语法,跟没有使用ts一样
var anyTypeVar = "8";
console.log(anyTypeVar);
anyTypeVar = 9;
console.log(anyTypeVar);
anyTypeVar = false;
console.log(anyTypeVar);
//any 类型的 可以任意使用属性和方法
console.log(anyTypeVar.hahaha);
console.log(anyTypeVar.hahaha.aaaaaa);
console.log(anyTypeVar.fun());
// any 结论:声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
//类型推论
/*
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类
型。
----也就是
1,第一次如果声明同时进行了赋值,那么推出对应的类型;
2.如果只声明则就是any类型
*/
var mytestVar = "seven";
// mytestVar = 7;
var mytestVar1;
mytestVar1 = 7;
mytestVar1 = "89898";
/*
联合类型(Union Types)表示取值可以为多种类型中的一种。
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型
里共有的属性或方法:
1. 就近原则 ---》最近一次的赋值 然后推断类型
*/
var myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// function getLength(something: string | number): number {
// return something.length;
// }
function getString(something) {
return something.toString();
}
// let tom:person;
var tom1 = {
name: "zhagnsna",
age: 89,
address: "hahaha"
};
var jerry;
jerry = {
width: 8989,
size: "haahha"
};
var jerry1 = {
size: "9999999"
};
var tom = {
name: 'Tom',
gender: 'male'
};
var tom222 = {
name: 'Tom',
gender: 'male'
};
// tom222.name = "ssss"
/*
数组 最简单的方法是使用「类型 + 方括号」来表示数组:
也可以指定一个any类型的数组:
*/
var arr = [1, 2, 3, 4, 5, 65];
console.log(arr);
arr.push(999);
console.log(arr);
// arr.push("sss")
// let arr2:number[] = ['1',2,3,4,5,65]
var list = ['xcatliu', 25, { website: 'http://xcatliu.com' }];
/*
函数声明
*/
// 函数声明(Function Declaration)
function sum(x, y) {
return x + y;
}
//,输入多余的(或者少于要求的)参数,是不被允许的:
function sum1(x, y) {
return x + y;
}
sum1(8, 9);
// sum1(8,9,111)
/*
函数表达式
*/
// 函数表达式(Function Expression)
var mySum = function (x, y) {
return x + y;
};
// 自动推断类型
var mySum2 = function (x, y) {
return x + y;
};
//手动设置类型
/*
(x: number, y: number) => number
这里的箭头是ts中的箭头 用来表示函数的定义 左边是输入类型,需要用括号括起来,右边是输出类型。
在 ES6 中, => 叫做箭头函数
*/
var mySum3 = function (x, y) {
return x + y;
};
var myFun;
myFun("aaa", "bbb");
var myFun1;
/*
优势:采用函数表达式|接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证
参数个数、参数类型、返回值类型不变。
*/
var myfun2 = function (input1, input2) {
return input1.toUpperCase() + input2.toUpperCase();
};
//函数 可选参数
/*
用 ? 表示可选的参数:
1.可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必需参数了:
*/
function buildName(firstName, lastName) {
if (lastName) {
return firstName + ' ' + lastName;
}
else {
return firstName;
}
}
var tomcat10 = buildName('Tom', 'Cat');
var tom10 = buildName('Tom');
/*
参数默认值
此时就不受「可选参数必须接在必需参数后面」的限制了:
*/
function buildName1(firstName, lastName) {
if (lastName === void 0) { lastName = 'Cat'; }
return firstName + ' ' + lastName;
}
var tomcat1 = buildName('Tom', 'Cat');
var tom111 = buildName('Tom');
function buildName2(firstName, lastName) {
if (firstName === void 0) { firstName = 'Tom'; }
return firstName + ' ' + lastName;
}
var tomcat22 = buildName('Tom', 'Cat');
var cat2222 = buildName(undefined, 'Cat');
/*
剩余参数
*/
function push(array) {
var items = [];
for (var _i = 1; _i < arguments.length; _i++) {
items[_i - 1] = arguments[_i];
}
items.forEach(function (item) {
array.push(item);
});
}
var a = [];
push(a, 1, 2, 3);
function reverse(x) {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
}
else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
/*
断言;在使用联合类型时只能访问公共的属性,如果已经确定要访问的属性,传入的参数无法区分,所以用断言来进行限定类型,去除联合类型的干扰
error as ApiError
值 as 类型
1. 在面对 如果类型时一个接口 的时候,必须使用as 来进行,不能使用instanceof
接口是一个类型,不是一个真正的值,它在编译结果中会被删除,当然就无法使用 instanceof 来做运行时判断了
2.对于 as any
来源:
1.可能是受到 TypeScript 类型系统的限制而无法精确定义类型的场景。
2.历史遗留的或其他人编写的烂代码
3.第三方库未能定义好自己的类型
一方面不能滥用 as any,另一方面也不要完全否定它的作用,我们需要在类型的严格性和开发的
便利性之间掌握平衡(这也是 TypeScript 的设计理念之一),才能发挥出 TypeScript 最大的价值。
联合类型可以被断言为其中一个类型
父类可以被断言为子类
任何类型都可以被断言为 any
any 可以被断言为任何类型
类型断言的限制
类型A中的属性与类型B中的属性必须有重叠,哪怕只有一个;就可以互相断言;
===============
双重断言
是不是可以使用双重断言 as any as Foo 来将任何一个类型断言为任何另一个类型呢?
若使用双重断言,则可以打破「要使得 A 能够被断言为 B ,只需要 A 兼容 B 或 B 兼容 A 即可」的限制,将任何一个类型断言为任何另一个类型。
除非迫不得已,千万别用双重断言。
类型断言语句在编译结果中会被删除;言只会影响 TypeScript 编译时的类型
类型断言不是类型转换,它不会真的影响到变量的类型。
//a断言为b时,a和b有重叠的部分即可
//a声明为b时,a必须具备b的所有属性和方法
类型声明是比类型断言更加严格的。
为了增加代码的质量,我们最好优先使用类型声明,这也比类型断言的 as 语法更加优雅。
*/
/*
any具有优势也有劣势,那么有更优的解决any的方案吗?
答案:添加一个泛型 ;用来规范对类型的限制
*/
function getCacheData(key) {
return window.cache[key];
}
var tom33 = getCacheData('tom');
tom.run();
function handleEvent(ele, event) {
// do something
}
handleEvent(document.getElementById('hello'), 'scroll'); // 没问题
// handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为
// 'dblclick'
/*
元组:数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
用中括号扩住类型 同时用中括号 扩住数据
初始化|赋值的时候必须给所有的类型赋值
添加元素的时候只能添加定义的联合类型的数据,其他类型的数据无法添加
*/
var tomm = ["shagn", 999];
console.log(tomm[0]);
console.log(tomm[1]);
/*
枚举类型
枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:
*/
var Days;
(function (Days) {
Days[Days["Sun"] = 0] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
;
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
/*
面向对象(OOP)的三大特性:封装、继承、多态
封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要
(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改
对象内部的数据
继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比
如 Cat 和 Dog 都继承自 Animal ,但是分别实现了自己的 eat 方法。此时针对某一个实例,我
们无需了解它是 Cat 还是 Dog ,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行
eat
抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的
抽象方法必须在子类中被实现
接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现
(implements)。一个类只能继承自另一个类,但是可以实现多个接口
使用 class 定义类,使用 constructor 定义构造函数。
通过 new 生成新实例的时候,会自动调用构造函数。
*/
var Animal1 = /** @class */ (function () {
function Animal1(name) {
this._name = name;
}
Animal1.prototype.sayHi1 = function () {
return "My name is ".concat(this._name);
};
return Animal1;
}());
var aaaa = new Animal1('wangwang');
console.log(aaaa.sayHi1());
//get set
var Animal111 = /** @class */ (function () {
function Animal111(name) {
this._name = name;
}
Animal111.prototype.getName = function () {
return 'Jack';
};
Animal111.prototype.setName = function (value) {
console.log('setter: ' + value);
};
return Animal111;
}());
var aaaaa = new Animal111('Kitty'); // setter: Kitty
aaaaa.setName("tom");
// = 'Tom'; // setter: Tom
console.log(aaaaa.getName()); // Jack
/*
静态方法
static修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:
*/
var Anmil1 = /** @class */ (function () {
function Anmil1(age) {
this._age = age;
}
Anmil1.sayhello = function (toPerson) {
return "hello ".concat(toPerson);
};
return Anmil1;
}());
var ccc = Anmil1.sayhello('张三');
// console.log(ccc._age);
// console.log(ccc._name);
// console.log(ccc._address);
/*
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定
类型的一种特性。
在类型后面使用尖括号包裹
把使用any 的地方换成 T 然后把返回值的类型也改成T【】
*/
function createArray(legth, value) {
var result = [];
for (var i = 0; i < legth; i++) {
result[i] = value;
}
return result;
}
createArray(8, 9);
/*
泛型的多个参数
跟在函数名称后面 入参,出参
使用元祖,返回元组,获取元组的下标
*/
function swap(tuple) {
return [tuple[0], tuple[1]];
}
swap(["llll", 9999]);
// T这个泛型不一定拥有length方法,所以使用extends 一个接口,使用对应接口具有的属性和方法
function longginIdentity(arg) {
console.log(arg.length);
return arg;
}
longginIdentity("7"); // 不报错
/*
泛型类
*/
var GenericNumber = /** @class */ (function () {
function GenericNumber() {
}
return GenericNumber;
}());
var myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) { return x + y; };
/*
泛型参数的默认类型
*/
function createArra111(length, value) {
var result = [];
for (var i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
/*
声明合并,同名函数、接口、类的合并
定义的名称相同,获取 并集,编译后出现的并集;但是不好维护,在各个文件中,慎用
*/
实战使用
vue2中如何使用TypeScript?
参考链接