一、基本数据类型
1.布尔类型(boolean)
var flag:boolean = true;
flag = false
3.数字类型(number)
var num:number = 123
3.字符串类型(string)
var str:string = 'this is ts'
str = 'haha'
4.数组类型(array)
ts中定义数组有两种方式
① 第一种定义数组的方式
var arr:number[] = [11,22,33]
console.log(arr)
var arr:Array<number> = [11,22,33]
② 第二种定义数组的方式
var arr:Array<number>=[11,22,33];
console.log(arr)
5.元组类型(tuple) 属于数组的一种
var arr:Array<number>=[11,22,33];
console.log(arr)
let arr:[number,string]=[123,'this is ts'];
console.log(arr);
6.枚举类型(enum)
随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据。
例如:性别、月份、星期几、颜色、单位名、学历、职业等,都不是数值数据。
在其它程序设计语言中,一般用一个数值来代表某一状态,这种处理方法不直观,易读性差。
如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。
也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,
这种方法称为枚举方法,用这种方法定义的类型称枚举类型。
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数],
} ;
enum Flag {success=1, error=2}
let s:Flag = Flag.success;
console.log(s)
enum Color {blue, red, 'orange'};
var c:Color=Color.blue;
console.log(c)
enum Err {'undefined'=1, 'null'=-2, 'success'=1}
var e:Err = Err.success;
console.log(e)
7.任意类型(any)
var num:any=123;
num='str';
num=true;
console.log(num)
//任意类型的用处
var oBox:any=document.getElementById('box');
oBox.style.color='red';
8.null 和 undefined
其他(never类型)数据类型的子类型
var num2:number;
console.log(num2)
var num3:undefined;
console.log(num3)
一个元素可能是 number类型 可能是null 可能是undefined,用|表示可能的数据类型
var num:number | null | undefined;
num=1234;
console.log(num)
9.void类型
typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。
//es5的定义方法
function run(){
console.log('run')
}
run();
//表示方法没有返回任何类型
function run():void{
console.log('run')
}
run();
10.never类型
是其他类型 (包括 null 和 undefined)的子类型,代表从不会出现的值
箭头函数返回的值可以定义为never类型
var a:never;
// a=123; //错误的写法
a=(()=>{
throw new Error('错误');
})()
二、TypeScript的函数
1、函数的定义
es5定义函数的方法
//函数声明法
function run(){
return 'run';
}
//匿名函数
var run2=function(){
return 'run2';
}
ts中定义函数的方法
//函数声明法
function run():string{
return 'run';
}
// 匿名函数
var fun2=function():number{
return 123;
}
alert(fun2()); /*调用方法*/
ts中定义方法传参
function getInfo(name:string,age:number):string{
return `${name} --- ${age}`;
}
alert(getInfo('zhangsan',20));
没有返回值的方法
function run():void{
console.log('run')
}
run();
2、方法可选参数
es5里面方法的实参和行参可以不一样,但是ts中必须一样,如果不一样就需要配置可选参数
function getInfo(name:string,age?:number):string{
if(age){
return `${name} --- ${age}`;
}else{
return `${name} ---年龄保密`;
}
}
alert(getInfo('zhangsan'))
alert(getInfo('zhangsan',123))
注意:可选参数必须配置到参数的最后面
3、默认参数 可选参数
// es5里面没法设置默认参数,es6和ts中都可以设置默认参数
function getInfo(name:string,age:number=20):string{
if(age){
return `${name} --- ${age}`;
}else{
return `${name} ---年龄保密`;
}
}
// alert( getInfo('张三'));
alert( getInfo('张三',30));
4、剩余参数
function sum(...result:number[]):number{
var sum=0;
for(var i=0;i<result.length;i++){
sum+=result[i];
}
return sum;
}
alert(sum(1,2,3,4,5,6)) ;
5、ts函数重载
// java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
// typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。
//ts为了兼容es5 以及 es6 重载的写法和java中有区别。
//es5中出现同名方法,下面的会替换上面的方法
function css(config){
}
function css(config,value){
}
function getInfo4(name:string):string;
function getInfo4(age:number):string;
function getInfo4(str:any):any{
if (typeof str === 'string') {
return "我叫:" + str;
} else {
return "我的年龄是" + str
}
}
console.log(getInfo4("张三"))
console.log(getInfo4(23))
6、箭头函数 es6
this指向的问题 箭头函数里面的this指向上下文
setTimeout(()=>{
alert('run')
},1000)
三、类
1、es5里面的类
1️⃣ 最简单的类
function Person() {
this.name = "张三";
this.age = 20;
}
var p = new Person()
console.log(p)
2️⃣构造函数和原型链里面增加方法
function Person(){
this.name='张三'; /*属性*/
this.age=20;
this.run=function(){
alert(this.name+'在运动');
}
}
//原型链上面的属性会被多个实例共享 构造函数不会
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
var p=new Person();
// alert(p.name);
// p.run();
p.work();
3️⃣ 类里面的静态方法
function Person3() {
this.name = "张三",
this.age = 20;
this.shit = function () {
console.log(this.name + "在拉屎")
}
// 静态方法
Person3.getInfo = function () {
console.log("我是静态方法")
}
// 原型链上面的属性会被多个实例共享 构造函数不会
Person3.prototype.sex = "男";
Person3.prototype.work = function () {
console.log(this.name + "在工作")
}
}
var p3 = new Person3();
// p3.work()
// Person3.getInfo()
4️⃣es5里面的继承 对象冒充实现继承
function Person(){
this.name='张三'; /*属性*/
this.age=20;
this.run=function(){ /*实例方法*/
alert(this.name+'在运动');
}
}
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
//Web类 继承Person类 原型链+对象冒充的组合继承模式
function Web(){
Person.call(this); /*对象冒充实现继承*/
}
var w=new Web();
// w.run(); //对象冒充可以继承构造函数里面的属性和方法
w.work(); //对象冒充可以继承构造函数里面的属性和方法 但是没法继承原型链上面的属性和方法
5️⃣es5里面的继承 原型链实现继承
function Person(){
this.name='张三'; /*属性*/
this.age=20;
this.run=function(){ /*实例方法*/
alert(this.name+'在运动');
}
}
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
//Web类 继承Person类 原型链+对象冒充的组合继承模式
function Web(){
}
Web.prototype=new Person(); //原型链实现继承
var w=new Web();
//原型链实现继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法
//w.run();
w.work();
6️⃣原型链实现继承的 问题?传参的时候找不到属性
function Person(name,age){
this.name=name; /*属性*/
this.age=age;
this.run=function(){ /*实例方法*/
alert(this.name+'在运动');
}
}
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
var p=new Person('李四',20);
p.run();
function Person(name,age){
this.name=name; /*属性*/
this.age=age;
this.run=function(){ /*实例方法*/
alert(this.name+'在运动');
}
}
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
function Web(name,age){
}
Web.prototype=new Person();
var w=new Web('赵四',20); //实例化子类的时候没法给父类传参
w.run();
// var w1=new Web('王五',22);
7️⃣原型链+对象冒充的组合继承模式
function Person(name,age){
this.name=name; /*属性*/
this.age=age;
this.run=function(){ /*实例方法*/
alert(this.name+'在运动');
}
}
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
function Web(name,age){
Person.call(this,name,age); //对象冒充继承 实例化子类可以给父类传参
}
Web.prototype=new Person();
var w=new Web('赵四',20); //实例化子类的时候没法给父类传参
// w.run();
w.work();
// var w1=new Web('王五',22);
8️⃣原型链+对象冒充继承的另一种方式
function Person(name,age){
this.name=name; /*属性*/
this.age=age;
this.run=function(){ /*实例方法*/
alert(this.name+'在运动');
}
}
Person.prototype.sex="男";
Person.prototype.work=function(){
alert(this.name+'在工作');
}
function Web(name,age){
Person.call(this,name,age); //对象冒充继承 可以继承构造函数里面的属性和方法、实例化子类可以给父类传参
}
Web.prototype=Person.prototype;
var w=new Web('赵四',20); //实例化子类的时候没法给父类传参
w.run();
// w.work();
// var w1=new Web('王五',22);
2.类的定义
es5:
function Person(name){
this.name=name;
this.run=function(){
console.log(this.name)
}
}
var p=new Person('张三');
p.run()
ts中定义类:
class Person{
name:string; //属性 前面省略了public关键词
constructor(n:string){ //构造函数 实例化类的时候触发的方法
this.name=n;
}
run():void{
alert(this.name);
}
}
var p=new Person('张三');
p.run()
3.继承
class Person{
name:string;
constructor(name:string){
this.name=name;
}
run():string{
return `${this.name}在运动`
}
}
// var p=new Person('王五');
// alert(p.run())
class Web extends Person{
constructor(name:string){
super(name); /*初始化父类的构造函数*/
}
}
var w=new Web('李四');
alert(w.run());
ts中继承的探讨 父类的方法和子类的方法一致, 子类覆盖父类的方法
4. 类里面的修饰符
typescript里面定义属性的时候给我们提供了 三种修饰符
public :公有 在当前类里面、 子类 、类外面都可以访问
protected:保护类型 在当前类里面、子类里面可以访问 ,在类外部没法访问
private :私有 在当前类里面可以访问,子类、类外部都没法访问
属性如果不加修饰符 默认就是 公有 (public)
class Person7{
public name:string; /*公有属性*/
constructor(name:string){
this.name=name;
}
run():string{
return `${this.name}在运动`
}
}
var p7=new Person7('王五');
console.log(p7.run())
class Web7 extends Person7{
constructor(name:string){
super(name); /*初始化父类的构造函数*/
}
work(){
console.log(`${this.name}在工作`)
}
}
var w7=new Web7('李四11');
w7.work();
console.log(w7.name)
console.log(w7.run());
5. 静态属性 静态方法
class Person {
public name:string;
public age:number=20;
// 静态属性
static sex = '男'
constructor(name:string) {
this.name = name;
}
run () { // 实例方法
console.log(`${this.name}在运动`)
}
work () {
console.log(`${this.name}在工作`)
}
static print () {
console.log('print方法' + Per.sex)
}
}
var person = new Per("张三")
// person.run()
// Person.print()
// console.log(Person.sex)
6. 多态 抽象类
1️⃣多态:父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现
class Animal {
name:string;
constructor(name:string) {
this.name=name;
}
eat(){ //具体吃什么 不知道 , 具体吃什么?继承它的子类去实现 ,每一个子类的表现不一样
console.log('吃的方法')
}
}
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃粮食'
}
}
class Cat extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃老鼠'
}
}
2️⃣抽象类:
//typescript中的抽象类:它是提供其他类继承的基类,不能直接被实例化。
//用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
// abstract抽象方法只能放在抽象类里面
// 抽象类和抽象方法用来定义标准 。 标准:Animal 这个类要求它的子类必须包含eat方法
//标准:
abstract class Animal{
public name:string;
constructor(name:string){
this.name=name;
}
abstract eat():any; //抽象方法不包含具体实现并且必须在派生类中实现。
run(){
console.log('其他方法可以不实现')
}
}
// var a=new Animal() /*错误的写法*/
class Dog extends Animal{
//抽象类的子类必须实现抽象类里面的抽象方法
constructor(name:any){
super(name)
}
eat(){
console.log(this.name+'吃粮食')
}
}
var d=new Dog('小花花');
d.eat();
四、接口
接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。定义标准。
1 属性类接口:
// 1-1.对json的约束
// ts中自定义方法传入参数,对json进行约束
function printLabel(labelInfo:{label:string}):void {
console.log("printLabel")
}
// printLabel({label: '张三'})
// 1-2.完整接口
//对批量方法传入参数进行约束。
//接口:行为和动作的规范,对批量方法进行约束
interface FullName {
firstName:string;
secondName:string;
}
function printName(name:FullName) {
console.log(name.firstName + '--' + name.secondName)
}
// printName({
// firstName: '张',
// secondName: '伟'
// })
// 1-3.可选属性
interface FullName2{
firstName:string;
secondName?:string;
}
function getName(name:FullName2){
console.log(name)
}
//参数的顺序可以不一样
// getName({
// firstName:'firstName'
// })
1-4.原生js封装的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 = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log("success")
if (config.dataType == 'json') {
console.log(JSON.parse(xhr.responseText))
} else {
console.log(xhr.responseText)
}
}
}
}
ajax({
type: 'get',
data: 'name=zhangsan',
url: 'http://a.itying.com/api/productlist',
dataType: 'json'
})
2 函数类型接口
对方法传入的参数 以及返回值进行约束
interface encrypt{
(key:string, value:string):string;
}
var md5:encrypt = function(key:string):string{
return key;
}
// console.log(md5('name', 'zhangsan'))
var sha1:encrypt=function(key:string,value:string):string{
//模拟操作
return key+'----'+value;
}
console.log(sha1('name','lisi'));
3 可索引接口
可索引接口:数组、对象的约束 (不常用)
ts定义数组的方式
var arr:number[] = [2342, 235325]
var arr1:Array<string> = ['111', '22222']
var arr2:Array<number> = [12,324]
1️⃣可索引接口 对数组的约束
interface UserArr {
[index: number]:string // 索引是数组,值是字符串
}
2️⃣可索引接口 对对象的约束
interface UserObj {
[index:string]:string
}
var arr4:UserObj = {name: "朱一旦"}
console.log(arr4['name'])
4 类类型接口
对类的约束 和抽象类抽象有点相似
interface Animal {
name:string;
eat(str:string):void // 实现类必须有这个方法
}
class Dog implements Animal {
name:string;
constructor(name:string) {
this.name = name
}
eat () {
console.log(this.name + '吃粮食')
}
}
var dog = new Dog("小黑")
// dog.eat()
5.接口扩展
1️⃣接口可以继承接口
interface Animal{
eat():void;
}
interface Person extends Animal {
work():void
}
class Web implements Person {
public name:string;
constructor(name:string) {
this.name = name
}
eat () {
console.log(this.name + '喜欢吃馒头')
}
work () {
console.log(this.name + '写代码')
}
}
var web = new Web('小李')
// web.work()
// web.eat()
2️⃣即继承类又实现接口
interface Animal2{
eat():void;
}
interface Person2 extends Animal2 {
work():void
}
class Programmer2{
public name:string;
constructor(name:string) {
this.name = name
}
coding(code:string) {
console.log(this.name + code)
}
}
class Web2 extends Programmer2 implements Person2 {
constructor(name:string){
super(name)
}
eat(){
console.log(this.name+'喜欢吃馒头')
}
work(){
console.log(this.name+'写代码');
}
}
var web2=new Web2('小王');
web2.coding('写ts代码');
五、泛型
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)
1 泛型的定义
//1-1. 定义一个函数返回string类型或者number类型,any可以解决这个问题,但舍弃了类型检查,即传入什么 返回什么。比如:传入number 类型必须返回number类型 传入 string类型必须返回string类型
function getData (value:any): any {
return '哈哈哈'
}
// getData(123)
// getData('str')
泛型:可以支持不特定的数据类型 要求:传入的参数和返回的参数一致
T表示泛型,具体什么类型是调用这个方法的时候决定的
function getData2<T> (value: T):T {
return value
}
console.log(getData2<string>('马勒戈壁'))
console.log(getData2<number>(3412))
2 泛型函数
同上
3 泛型类
比如有个最小堆算法,需要同时支持返回数字和字符串 a-z两种类型。通过类的泛型来实现
class MinClass<T> {
public list:T[] = []
add(value:T):void {
this.list.push(value)
}
min():T {
var minNum = this.list[0]
for (var i = 0; i < this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i]
}
}
return minNum;
}
}
var m1 = new MinClass<number>()
m1.add(11)
m1.add(3)
m1.add(2)
// console.log(m1.min())
var m2 = new MinClass<string>()
m2.add('c')
m2.add('a');
m2.add('v');
// console.log(m2.min())
4 泛型接口
定义接口的时候不确定数据类型
1️⃣函数类型接口
interface ConfigFn {
<T>(value:T):T;
}
var getData3:ConfigFn = function<T>(value:T):T {
return value
}
console.log(getData3<string>("张三"))
console.log(getData3<number>(1445))
2️⃣ 泛型案例:操作数据库
2-1.把类作为参数来约束数据传入的类型:将User类作为参数传给MysqlDb
class User {
username:string | undefined;
password:string | undefined;
}
class MysqlDb {
add(user:User):boolean{
console.log(user)
return true
}
}
var u = new User()
u.username = "张三"
u.password = '123456'
var Db = new MysqlDb();
Db.add(u)
// 问题:代码重复,这个时候再来一个ArticleCate,又要重新定义一个接收ArticleCate的MysqlDb类
2-2.定义操作数据库的泛型类,不用声明传入的是哪个类
class MysqlDb2<T> {
add(info:T):boolean{
console.log(info)
return true
}
updated(info:T, id:number):boolean{
console.log(info)
console.log(id)
return true
}
}
class User2{
username:string | undefined;
password:string | undefined;
}
var u2 = new User2 ();
u2.username = '你爸'
u2.password = '8888888'
var Db2 = new MysqlDb2<User2>()
Db2.add(u2)
Db2.updated(u2, 2333)
2-3.定义一个操作数据库的库 支持 Mysql Mssql MongoDb
要求1:Mysql MsSql MongoDb功能一样 都有 add update delete get方法
注意:约束统一的规范、以及代码重用
解决方案:需要约束规范所以要定义接口 ,需要代码重用所以用到泛型
- 接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
- 泛型 通俗理解:泛型就是解决 类 接口 方法的复用性、
interface DBI<T> {
add(info:T):boolean;
update(info:T, id:number):boolean;
delete(id:number):boolean;
get(id:number):any[];
}
//定义一个操作mysql数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型类,换一个数据库也是一样实现泛型接口
class MysqlDb3<T> implements DBI<T> {
constructor() {
console.log('数据建立连接')
}
add(info: T) {
console.log(info)
return true
}
update(info:T, id:number): boolean {
throw new Error("Method not implement")
}
delete(id:number): boolean{
throw new Error("Method not implement")
}
get(id: number):any [] {
var list = [
{
title: 'xxx',
desc: 'xxxxxxxxx'
},
{
title: 'xxx',
desc: 'xxxxxxxxx'
}
]
return list
}
}
class User3 {
username:string | undefined;
password:string | undefined;
}
var u3=new User3();
u3.username='张三111';
u3.password='123456';
var oMysql3 = new MysqlDb3<User>()
oMysql3.add(u3)
console.log(oMysql3.get(1))
// 这时来了另一个数据库MsSqlDb,同样适用
六、模块
1 模块的的概念
模块的的概念(官方):
关于术语的一点说明: 请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。“外部模块”现在则简称为“模块” 模块在其自身的作用域里执行,而不是在全局作用域里;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用 import形式之一。
模块的概念(自己理解):我们可以把一些公共的功能单独抽离成一个文件作为一个模块。模块里面的变量 函数 类等默认是私有的,如果我们要在外部访问模块里面的数据(变量、函数、类),我们需要通过export暴露模块里面的数据(变量、函数、类...)。暴露后我们通过 import 引入模块就可以使用模块里面暴露的数据(变量、函数、类...)。
var dbUrl = 'xxxxxx'
function getData():any[]{
console.log("获取数据库的数据111")
return [
{
title: '迪丽热🐎'
},
{
title: '古力娜扎'
}
]
}
function save() {
console.log("保存数据成功")
}
export {dbUrl, getData, save}
import {dbUrl, getData as get} from './modules/db'
console.log(dbUrl)
get();
2 模块导出的几种方法(不详细写)
1、export 导出声明
2、export 导出语句
3、export default
4、import导入模块
3 模块化封装上一讲的DB库
db.ts:封装了对数据库的操作,使用了泛型,可适用于不同的数据库
interface DBI<T>{
add(info:T):boolean;
update(info:T,id:number):boolean;
delete(id:number):boolean;
get(id:number):any[];
}
//定义一个操作mysql数据库的类 注意:要实现泛型接口 这个类也应该是一个泛型类
export class MysqlDb<T> implements DBI<T>{
constructor(){
console.log('数据库建立连接');
}
add(info: T): boolean {
console.log(info);
return true;
}
update(info: T, id: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
var list=[
{
title:'xxxx',
desc:'xxxxxxxxxx'
},
{
title:'xxxx',
desc:'xxxxxxxxxx'
}
]
return list;
}
}
article.ts: 实体类,在MsSqlDb数据库进行读写
import {MsSqlDb} from '../modules/db';
//定义数据库的映射
class UserClass{
username:string | undefined;
password:string | undefined;
}
var UserModel=new MsSqlDb<UserClass>();
export {
UserClass,UserModel
}
user.ts:实体类,在MsSqlDb数据库进行读写
import {MsSqlDb} from '../modules/db';
//定义数据库的映射
class UserClass{
username:string | undefined;
password:string | undefined;
}
var UserModel=new MsSqlDb<UserClass>();
export {
UserClass,UserModel
}
index.ts: 具体操作
import {UserClass, UserModel} from './model/user'
import {ArticleClass, ArticleModel} from './model/article'
// 增加数据
var u = new UserClass()
u.username = '张三'
u.password = '121212144';
UserModel.add(u)
// 获取user表数据
// var res = UserModel.get(123)
// console.log(res)
// 获取文章表的数据
// var aRes = ArticleModel.get(1464)
// console.log(aRes)
七、命名空间
命名空间:
在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内
同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export关键字对外暴露。
命名空间和模块的区别:
命名空间:内部模块,主要用于组织代码,避免命名冲突。
模 块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。
namespace A {
interface Animal {
name:string;
eat(): void;
}
export class Dog implements Animal {
name:string;
constructor(theName: string) {
this.name = theName
}
eat () {
console.log(`${this.name} 在吃狗粮。`)
}
}
export class Cat implements Animal {
name:string;
constructor(theName: string) {
this.name = theName
}
eat () {
console.log(`${this.name} 在吃猫粮。`)
}
}
}
namespace B {
interface Animal {
name:string;
eat(): void;
}
export class Dog implements Animal {
name:string;
constructor(theName: string) {
this.name = theName
}
eat () {
console.log(`${this.name} 在吃狗粮2。`)
}
}
export class Cat implements Animal {
name:string;
constructor(theName: string) {
this.name = theName
}
eat () {
console.log(`${this.name} 在吃猫粮2。`)
}
}
}
var c = new A.Cat("小花")
c.eat()
八、装饰器
装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参) 、 装饰器工厂(可传参)
装饰器是过去几年中js最大的成就之一,已是Es7的标准特性之一
1、类装饰器
类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 传入一个参数
1️⃣类装饰器:普通装饰器(无法传参)
function logClass(params:any){
console.log(params);
// params 就是当前类
params.prototype.apiUrl='动态扩展的属性';
params.prototype.run=function(){
console.log('我是一个run方法');
}
}
@logClass
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.run();
2️⃣类装饰器:装饰器工厂(可传参)
function logClass(params:string){
return function(target:any){
console.log(target);
console.log(params);
target.prototype.apiUrl=params;
}
}
@logClass('http://www.itying.com/api')
class HttpClient{
constructor(){
}
getData(){
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
3️⃣类装饰器-重载构造函数
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
function logClass(target:any){
console.log(target);
return class extends target{
apiUrl:any='我是修改后的数据';
getData(){
this.apiUrl=this.apiUrl+'----';
console.log(this.apiUrl);
}
}
}
@logClass
class HttpClient{
public apiUrl:string | undefined;
constructor(){
this.apiUrl='我是构造函数里面的apiUrl';
}
getData(){
console.log(this.apiUrl);
}
}
var http=new HttpClient();
http.getData();
2、属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
function logProperty(params:any){
return function(target:any,attr:any){
console.log(target);
console.log(attr);
target[attr]=params;
}
}
@logClass('属性被人改了')
class HttpClient{
@logProperty('http://itying.com')
public url:any |undefined;
constructor(){
}
getData(){
console.log(this.url);
}
}
var http=new HttpClient();
http.getData();
3、方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
3、成员的属性描述符。
1️⃣ 方法装饰器一
function get(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc);
target.apiUrl='xxxx';
target.run=function(){
console.log('run');
}
}
}
class HttpClient{
public url:any |undefined;
constructor(){
}
@get('http://www.itying,com')
getData(){
console.log(this.url);
}
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.run();
2️⃣方法装饰器二
function get(params:any){
return function(target:any,methodName:any,desc:any){
console.log(target);
console.log(methodName);
console.log(desc.value);
//修改装饰器的方法 把装饰器方法里面传入的所有参数改为string类型
//1、保存当前的方法
var oMethod=desc.value;
desc.value=function(...args:any[]){
args=args.map((value)=>{
return String(value);
})
oMethod.apply(this,args);
}
}
}
class HttpClient{
public url:any |undefined;
constructor(){
}
@get('http://www.itying,com')
getData(...args:any[]){
console.log(args);
console.log('我是getData里面的方法');
}
}
var http=new HttpClient();
http.getData(123,'xxx');
4、方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、方法的名字。
3、参数在函数参数列表中的索引。
function logParams(params:any){
return function(target:any,methodName:any,paramsIndex:any){
console.log(params);
console.log(target);
console.log(methodName);
console.log(paramsIndex);
target.apiUrl=params;
}
}
class HttpClient7{
public url:any |undefined;
constructor(){
}
getData(@logParams('xxxxx') uuid:any){
console.log(uuid);
}
}
var http7:any = new HttpClient7();
http7.getData(123456);
console.log( http7.apiUrl);
5、装饰器执行顺序
- 属性 > 方法 > 方法参数 > 类
- 如果有多个同样的装饰器,它会先执行后面的
function logClass1(params:string){
return function(target:any){
console.log('类装饰器1')
}
}
function logClass2(params:string){
return function(target:any){
console.log('类装饰器2')
}
}
function logAttribute1(params?:string){
return function(target:any,attrName:any){
console.log('属性装饰器1')
}
}
function logAttribute2(params?:string){
return function(target:any,attrName:any){
console.log('属性装饰器2')
}
}
function logMethod1(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法装饰器1')
}
}
function logMethod2(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法装饰器2')
}
}
function logParams1(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法参数装饰器1')
}
}
function logParams2(params?:string){
return function(target:any,attrName:any,desc:any){
console.log('方法参数装饰器2')
}
}
@logClass1('http://www.itying.com/api')
@logClass2('xxxx')
class HttpClient{
@logAttribute1()
@logAttribute2()
public apiUrl:string | undefined;
constructor(){
}
@logMethod1()
@logMethod2()
getData(){
return true;
}
setData(@logParams1() attr1:any,@logParams2() attr2:any,){
}
}
var http:any=new HttpClient();