TS
-邂逅TS
(二)
不积跬步,无以至千里;不积小流,无以成江海。💪🏻
一、接口(interface
)
在
ts
中,子类只能继承一个父类,不可多继承,但是接口可以实现多继承。So
,请小萝卜儿们继续往下看哦 👇🏻
- 作用 👍🏻:接口是为了实现多继承,接口好比协议,我们签署了协议,就需要实现协议上的内容。
- 多继承:子类可以继承多个父类,从而同时含有多个类的属性。
- 使用 🎀:将需要继承的多个父类用 接口 表示。
- 定义接口 🦋:( interface )
interface 接口名 { }
- 定义继承 父接口 的 子接口 🦋:( extends )【多个父接口用 逗号 隔开】
interface 子接口 extends 父接口1, 父接口2 { }
- 定义继承 父接口 的 子类 🦋:( implements )【多个父接口用 逗号 隔开】
class 子类 implements 父接口1, 父接口2 { }
注意: ⏰
- 1、无论子接口还是父接口,里面的方法都要写成不被实现的,比如:
attack();
;- 2、接着在继承接口的子类里必须实现该接口里的方法,比如:
attack() { }
。
父类:人、狼、猪猪;
子类:狼人;
实现效果:定义一个子类狼人,其既含有人的属性,也含有狼、猪猪的属性。
第一步🪜、定义三个父类(人、狼、猪猪)
// 父类-人
class Person {
name: string = "杨咩咩";
}
// 父类-狼
// class Wolf {
// attack() {
// }
// }
// 为了实现多继承,Wolf就不能用类了,而要写成一个接口 👇🏻
// IWolf:命名习惯,前加个I,表示这个是个接口,而不是一个普通的类
interface IWolf {
// 注意这里的方法要写成不被实现的
attack(): any;
}
// 父类-猪猪
// 为了实现多继承,不能用类了,而要写成一个接口 👇🏻
// IPig:命名习惯,前加个I,表示这个是个接口,而不是一个普通的类
interface IPig {
// 注意这里的方法要写成不被实现的
eat(): any;
}
第二步 🪜、定义一个子类狼人,其既含有人的属性,也含有狼、猪猪的属性
1)、方法一 🍓
直接通过
extends
继承父类Person
,同时通过implements
继承父接口IWolf
、IPig
实现。
// 子类-狼人
// 想实现一个类WolfMan 同时含有Person、Wolf、Pig的特性
// WolfMan是Person的子类,同时还拥有IWolf、IPig的特性
class WolfMan extends Person implements IWolf, IPig {
// 必须实现接口里的方法
attack() {
console.log('attack')
}
eat() {
console.log('eat')
}
// 构造函数
constructor() {
super();
this.name = "新的杨咩咩";
}
}
2)、方法二 🍊
1、先通过
extends
定义一个接口IChild
,其继承IWolf
、IPig
接口;
2、再通过extends
继承父类Person
,同时通过implements
继承接口IChild
实现。
// 定义一个接口IChild,其继承IWolf、IPig接口
// IChild:命名习惯,前加个I,表示这个是个接口,而不是一个普通的类
interface IChild extends IWolf, IPig {
// 注意这里的方法要写成不被实现的
// cry(): any;
}
// 子类-狼人
// 想实现一个类WolfMan 同时含有Person、Wolf、Pig的特性
// WolfMan是Person的子类,同时还拥有IWolf、IPig的特性
class WolfMan extends Person implements IChild {
// 必须实现接口里的方法
// cry() {
// console.log('cry')
// }
attack() {
console.log('attack')
}
eat() {
console.log('eat')
}
// 构造函数
constructor() {
super();
this.name = "新的杨咩咩";
}
}
二、属性寄存器(get
、set
)
- 取值:
get
- 赋值:
set
实现不在外部直接修改成员属性
_hp
。
// 类 Person
class Person {
// 成员属性
_hp: number = 120;
// 取值
get hp() {
return this._hp;
}
// 赋值
set hp(value) {
if(value < 0) {
this._hp = 0;
} else {
this._hp = value;
}
}
}
// 外部
// 实例化对象 new一下
let a = new Person();
// 有属性寄存器的情况下,就尽量不要去用成员属性_hp
// 赋值
a.hp -= 100;
// 取值
document.write(a.hp + ""); // 20
三、命名空间(namespace
)
目的 🌈:解决命名冲突;
使用 📚:在同名类外面包裹一层namespace 自定义名称 { }
;
注意 🌩:如果一个类想在名称空间外被使用,需要在类前面加个export
。
// 命名空间:解决命名冲突
/**
* 举例:假如有两个都叫Person的类,想分别获取到对应类的name值
*/
/** 通过命名空间namespace对类进行区分 */
namespace aa {
// 如果一个类想在名称空间外被使用,需要在类前面加个 export
export class Person {
name: string = "111";
}
}
namespace bb {
// 如果一个类想在名称空间外被使用,需要在类前面加个 export
export class Person {
name: string = "222";
}
}
/** 实例化对象,分别获取到对应类的name值 */
let person1 = new aa.Person();
document.write(person1.name); // 111
let person2 = new bb.Person();
document.write(person2.name); // 222
四、泛型
- 格式 🏠:
<类型>
; - 目的 📚:1、方便管理 (使用泛型后,只用在调用方法或类时修改表明的类型,该方法或类里用到该类型的地方就都被改到了);2、实现类型统一化
- 可能有爱动脑筋的小萝卜儿想到:类型都传
any
就好啦。 - 这样确实不用区分类型了,
But
要注意哦:- 比如:
function add(num: any): any{ }
都用类型any
会导致一个问题,传进的类型是number
,但传出的类型是string
,达不到类型的统一化哦。
- 比如:
- 可能有爱动脑筋的小萝卜儿想到:类型都传
- 使用 😇 :下面分别对单泛型和多泛型写了对应案例,请往下看哦~ 👇🏻
1、单泛型 ⭐️
/** 单泛型 */
// 1、自定义待传入的类型T(T是随便取的)
// 传进和传出的类型为同类型T,从而实现:传进什么类型,传出的就是什么类型
function add<T>(num: T): T {
if(typeof num === 'number') {
num++;
return num;
}
return num;
}
// 2、调用方法时要在<>里传入对应类型
// 比如这儿相当于:T对应的是number数值型
document.write(add<number>(3) + ''); // 4
// 比如这儿相当于:T对应的是string字符串型
document.write(add<string>('3') + ''); // 3
2、多泛型 ⭐️
/** 多泛型 */
// 1、自定义待传入的类型T、S(T, S就是随便取的)
// 假如想有多个类型,把多个泛型用逗号隔开即可,比如<T,S>
class Person<T,S> {
// 成员方法
say(num: T) {
// document.write()里面只能接字符串型,无论什么类型,只要跟个 + "",就会变成字符串型哦
document.write(num + "");
}
// 成员方法
eat(food: S) {
// document.write()里面只能接字符串型,无论什么类型,只要跟个 + "",就会变成字符串型哦
document.write(food + "");
}
}
// 2、实例化对象时要在<>里传入对应类型,传入时前后顺序需要一一对应,比如这儿相当于:T对应的是number数值型,S对应的是string字符串型
let a = new Person<number,string>;
a.say(3); // ✅ 3
a.say('3'); // ❎ ('3'下方出现红色波浪线) Error: Argument of type 'string' is not assignable to parameter of type 'number'.
a.eat('棒棒糖'); // ✅ '棒棒糖'
a.eat(0); // ❎ (0下方出现红色波浪线) Error: Argument of type 'number' is not assignable to parameter of type 'string'.
五、元祖(Tuple
)、数组(Array
)、字典
- 1、元祖(
Tuple
): 一个固定长度
、合并不同类型
的 数组。- 语法 🎀 :
[类型1, 类型2]
- 举例 🎀 :const hero:
[string, number]
= [“超人”,100];
- 语法 🎀 :
- 2、数组(
Array
):长度不固定
、合并相同类型的内容
。- 数组的声明方式有两种 【更多详情可看TS-邂逅TS(一)】:👇🏻
- 1、
类型[]
,比如number[]
表示数值型数组,eg. [1,2,3]; - 2、
Array<类型>
,比如Array<number>
表示数值型数组,eg. [1,2,3]。
- 1、
- 数组的声明方式有两种 【更多详情可看TS-邂逅TS(一)】:👇🏻
- 3、字典
1、元祖(Tuple
)
// 比如hero是一个元祖类型,里面存了两个数据,一个是字符串类型,一个是数值型
let hero: [string, number] = ["超人",100];
hero[0] = "蝙蝠侠";
document.write(hero[0]); // 蝙蝠侠
2、数组(Array
)
/* 数组的声明方式有两种:
1、类型[],比如 number[] 表示数值型数组,比如[1,2,3]
2、Array<类型>,比如 Array<number> 表示数值型数组,比如[1,2,3]
*/
const array1: number[] = [1,2,3];
// 下面的Array是个类,new Array()为一个空数组[]
// 下面的<number>是泛型,限制了数组里面的值类型为number
const array2: Array<number> = new Array<number>();
(一)、数组里添加或删除元素的方法:push()
、unshift()
、pop()
、shift()
、splice()
const array = [1,2,3];
// 1、push() 在数组最后面追加元素(可以追加多个元素)
array.push(4, 5);
console.log(array); // [1, 2, 3, 4, 5]
// 2、unshift() 在数组最前面添加元素(可以添加多个元素)
array.unshift(-1, 0);
console.log(array); // [-1, 0, 1, 2, 3, 4, 5]
// 3、pop() 删除数组中的最后一个元素
array.pop();
console.log(array); // [-1, 0, 1, 2, 3, 4]
// 4、shift() 删除数组中的第一个元素
array.shift();
console.log(array); // [0, 1, 2, 3, 4]
// 5、splice() 删除元素/插入元素/替换元素(第一个参数是操作元素的索引值)
// (1)、删除元素:第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
array.splice(0, 1); // 从第一位开始删除1个元素
console.log(array); // [1, 2, 3, 4]
// (2)、插入元素:第二个参数为0(删除0个),并且第三个参数是表示要插入的元素
array.splice(0, 0, 6); // 在索引值为0的地方插入6
console.log(array); // [6, 1, 2, 3, 4]
// (3)、替换元素:第二个参数,表示我们要替换几个元素,第三个元素是用于替换前面的元素
array.splice(0, 2, 7); // 7替换掉从第一位开始的两个元素
console.log(array); // [7, 2, 3, 4]
(二)、合并数组的方法
/**
* 合并两个数组的方法:
* 方法1、数组1.concat(数组2);
* 方法2、[...数组1,...数组2];
*/
const array1 = [2,3];
const array2 = [1,2,3];
// 方法1
const finalArray1 = array1.concat(array2);
console.log(finalArray1); // [2, 3, 1, 2, 3]
// 方法2
const finalArray2 = [...array1,...array2];
console.log(finalArray2); // [2, 3, 1, 2, 3]
(三)、查找数组中元素的位置(索引值):indexOf()
/**
* 查找数组中元素的位置(索引值)
* 语法: 数组.indexOf(待查找元素);
*/
const array = [1,3,2,3,2];
const index = array.indexOf(3);
console.log(index); // 1
(四)、数组排序:sort()
、reverse()
/**
* 排序
* 1、顺序: 数组.sort();
* 2、逆序: 数组.reverse();
*/
const array = [1,3,2,3,2];
// 顺序
array.sort();
console.log(array); // [1, 2, 2, 3, 3]
// 逆序
array.reverse();
console.log(array); // [3, 3, 2, 2, 1]
3、字典
// ["a","b","c"] => key: value 0: "a" 1: "b" 2: "c"
// 字典
let dic: { [key: string]: string } = {
"name1": "王小虎",
"name2": "李逍遥",
};
dic["name3"] = "令狐冲";
document.write(dic["name3"]); // 令狐冲
六、访问修饰符
- 共有三个 👇🏻:放在 属性和方法(包括:成员属性、成员方法、构造方法、静态属性、静态方法) 前面,限定属性和方法的访问权限。【默认是
public
:前面什么也不加 等于 前面加public
】-
- public(公开的):完全公开访问,类里的属性和方法在
当前类
、子类
、外部
均可访问;
- public(公开的):完全公开访问,类里的属性和方法在
-
- protected(受保护的):类里的属性和方法在
当前类
、子类
可访问,在外部
不可访问;
- protected(受保护的):类里的属性和方法在
-
- private(私有的):类里的属性和方法在
当前类
可访问,在子类
、外部
均不可访问。
- private(私有的):类里的属性和方法在
-
/** 以public为例 */
// 当前类 Person
class Person {
// 成员属性【默认是public:前面什么也不加 等于 前面加public】
name: string = "小猪";
// 成员方法【默认是public:前面什么也不加 等于 前面加public】
say() {
document.write(this.name);
}
}
// 子类 Student
class Student extends Person {
constructor() {
super();
this.name = "乔治";
this.say(); // 乔治
}
}
// 外部
let a = new Person(); // 实例化对象
a.name = "佩奇";
a.say(); // 佩奇
new Student(); // 实例化对象
上一篇:TS-邂逅TS(一)
今日份TS
学习到此结束啦 拜了个拜~