Class类-属性方法(字段)
Class类
类是用于 创建对象 模板。 同时类声明也会引入一个 新类型,可定义其 实例属性、方法和构造函数。
学习目录:
1、Class类 实例属性
// 定义类名
class Cat {
name: string = 'Tom'
foods?: string
}
// 基于类,创建对象
let p: Cat = new Cat()
console.log('姓名:', p.name)
// ?. ==> 可选链操作符 如果p.foods真有值,那就取length,如果没有值就取的是foods本身,不调用length
console.log('食物:', p.foods?.length)
p.foods = '小黄鱼'
console.log('食物:', p.foods?.length)
2、Class类 构造函数
3、Class类 定义方法
// 定义类名
class Cat {
// 1、定义属性、变量
name: string = 'Tom'
foods?: string
}
// 基于类,创建对象
let p: Cat = new Cat()
// console.log('姓名:', p.name)
// ?. ==> 可选链操作符 如果p.foods真有值,那就取length,如果没有值就取的是foods本身,不调用length
// console.log('食物:', p.foods?.length)
p.foods = '小黄鱼'
// console.log('食物:', p.foods?.length)
// 简易用接口
interface IFood {
name: string
price: number
desc: string
}
// 复杂用class
class Food {
name: string
price: number
desc: string
// 2、构造方法 希望不同的实例,有不同的字段初始化值 --> 构造函数
constructor(paramsFood: IFood) {
this.name = paramsFood.name
this.price = paramsFood.price
this.desc = paramsFood.desc
}
// 3、定义方法
printFoods(): string {
console.log('printFoods: name:',this.name, ",price:", this.price, ",desc:" ,this.desc)
return 'printFoods: name:' + this.name + ",price:" + this.price + ",desc:" + this.desc
}
}
let f1: Food = new Food({
name: '西兰花',
price: 2,
desc: '好吃'
})
let f2: Food = new Food({
name: '黄瓜',
price: 5,
desc: '清爽'
})
console.log('f1:',f1.printFoods())
console.log('f2:',f2.printFoods())
4、静态属性 和 静态方法
// 存取版本号、工具方法
class Rebot {
// 静态属性和静态方法
static version: number = 1.0
static getRandom(): number {
return Math.random()
}
}
console.log('version:', Rebot.version)
console.log('getRandom():', Rebot.getRandom())
5、继承 extends 和 super 关键字
类可以通过 继承 快速获取另一个类的 字段 和 方法
// 父类 子类
// 人类 学生、老师、工人
class Person {
name: string
age: number
constructor(name:string, age:number) {
this.name = name
this.age = age
}
sayHi() {
console.log('大家好~', this.name, this.age)
}
}
class Student extends Person {
grade: string
constructor(name: string, age: number, grade: string) {
// 父类中的构造函数 此时需要我们手动去调用 super.方法名() super.属性名
super(name, age)
// 完成自己的属性初始化
this.grade = grade
}
study() {
console.log('我是学生,我爱学习')
}
sayHi() {
super.sayHi()
console.log('Hello Nice to Meet you')
}
}
let s1 = new Student('Tom', 20, '三年级')
s1.sayHi()
console.log(s1.grade)
s1.study()
class Teacher extends Person {
}
let s2 = new Teacher('TomTeacher', 21)
s2.sayHi()
class Worker {
}
6、instanceof 检测是否实例
typeof 基础类型 instanceof 对象类型
console.log(typeof 111)
console.log(typeof true)
class Person{}
class Student extends Person{}
class Worker extends Person{}
let p = new Person()
let s = new Student()
console.log(typeof p) // object
console.log(typeof s) // object
// typeof 仅能用于判断简单类型 复杂类型则需用instanceof判断
console.log('判断结果:', p instanceof Person) // true
console.log('判断结果:', s instanceof Student) // true
console.log('判断结果:', s instanceof Person) // true
console.log('判断结果:', s instanceof Worker) // false
interface IObj{}
// 判断一个变量是不是数组类型
let temp = []
console.log('判断结果:', temp instanceof Array) // true
let iObj: IObj = {}
console.log('判断结果:', iObj instanceof Array) // false
7、修饰符 (readonly 、 private、protected)
protected:派生类/子类可以访问
private:只有自己类内部可以自己访问 其它均不能访问
源代码:
age: number
// 可读不能修改
readonly legs: number = 4
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
let c1 = new Cat('小花', 2)
// c1.legs = 6 // 不能修改
class Person{
private name:string = ''
private age:number = 0
desc: string = ''
sayHi() {
// private:内部可以访问
console.log(this.name)
}
}
let p1 = new Person()
console.log(p1.desc) // 无法在外部访问私有数据
class Student extends Person{
sayHi(){
console.log(super.desc) // 私有数据子类无法访问
}
}
8、剩余参数 和 展开运算符
// ...数组名 ===> 可以收集剩余的参数
function sum(n1:number, n2:number, ...argsArr: number[]): number {
let total = n1 + n2
// 遍历剩余的参数,如果有剩余的参数,就继续累加
for(let temp of argsArr) {
total+= temp
}
console.log('结果', total)
return total
}
console.log('1+2的和:' + sum(1,2))
sum(1,2,3,4,5,6,7)
// ArtTs中 展开运算符只能是合并数组的
let ar1:number[] = [1,2,3]
let ar2:number[] = [4,5,6]
let newArr:number[] = [...ar1, ...ar2]
console.log('最终的数组', newArr)
interface接口的继承和实现
接口继承使用的关键字是extends
源代码:
interface IAnimal {
name: string
age: number
}
interface IDog extends IAnimal {
color: string
}
interface ICat extends IAnimal {
hair: string // 毛发
}
let dog1: IDog = {
name: '小泰迪',
age: 2,
color: '棕色'
}
console.log('dog:', dog1.name)
接口的实现:
可以通过接口结合 implements 来限制 类 必须要有 某些属性 和 方法
// 定义一个接口,约束类 ---》 类需要按照接口的需求,实现类的主体
interface IDog {
name: string
age: number
jump: () => void
}
// 基于接口,实现类
class Dog implements IDog {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
jump() {
console.log('jump')
}
}
let dog1 = new Dog('小黑', 1)
dog1.jump()
==================================
泛型:
泛型可以让函数等,与多种不同的类型一起工作,灵活可复用
通俗一点就是:类型是 可变 的
泛型函数
// 封装一个函数:传入什么样的参数,就立刻返回什么样的参数
function fn<T> (param: T) : T {
return param
}
fn<string>('abc')
fn<number>(1)
fn<boolean>(false)
fn<number[]>([1,2,3,4,5])
// ArtTs 会根据默认根据传参,进行类型推断,动态的配置 T 类型参数 的值
// 练习1:定义一个函数,参数是数组(存的类型不定),返回数组的长度
function getLength<T> (arr: T[]) : number {
return arr.length
}
console.log('数组长度:', getLength<number>([1,2,3]))
console.log('数组长度:', getLength<string>(['a']))
// 练习1:定义一个函数,参数是数组(存的类型不定),返回数组的最后一项
function getLast<T> (arr: T[]) : T {
return arr[arr.length - 1]
}
console.log('数组最后一项:', getLast<number>([1,2,3,99]))
泛型约束
之前的类型参数,可以传递任何类型,没有限制。
如果希望有限制 ---> 泛型约束。
// 泛型约束: 给传递的参数类型,添加限制
interface ILength {
length: number
}
function fn<T extends ILength>(param : T) {
console.log('', param.length)
}
fn<string>('123')
fn<number[]>([1,2,3,4])
class Desk {
length = 2
}
let d = new Desk()
fn(d)
多个泛型参数
// 多个泛型参数
function fn<T1,T2> (param1: T1, param2: T2) {
console.log('参数1:', param1, ', 参数2:', param2)
}
fn('abc', false)
fn(['abc', 'def'], false)
fn(['abc', 'def'], [1,2,3,4])
泛型接口/泛型类
// 泛型接口
// 定义接口的时候,结合泛型定义,就是泛型接口。
interface IdFunc<T> {
// 约定两个方法(id类型不定, string number)
// 1、传入 id 值, 就返回 id 值
// 2、返回一个 ids 数组
id: (value: T) => T
ids: () => T[]
}
let obj:IdFunc<number> = {
id(value: number) {
return value
},
ids() {
return [1,2,3]
}
}
// 泛型类
// 定义类的时候,结合泛型定义,就是泛型类
class Person<T> {
id: T
constructor(id: T) {
this.id = id
}
getId() : T {
return this.id
}
}
let person: Person<number> = new Person<number>(1)
console.log('personId:', person.getId())
=====
模块化语法:
1、模块化基本认知
模块化:把一个大的程序,【拆分】成若干的小的模块,通过【特定的语法】,可以进行任意组合。
ArkTS中的每个 ets文件,都可以看做是一个模块
2、默认导入和导出
默认导出:指一个模块,只能默认导出的 一个值或对象。使用时,可以 自定义 导入名称。
使用步骤:
1、当前模块中 导出模块。
2、需要使用的地方 导入模块。
// 默认导出
export default 需要导出的内容
// 默认导入
import xxx from '模块路径'
源代码:
module1.ets:
interface Person {
name: string
age: number
}
// 一个ets 文件,就是一个模块,每个模块之间独立
let num: number = 10
let person: Person = {
name: 'json',
age: 18
}
// 默认导出(导出一个值)
// export default num
export default person
module2.ets:
const fn = ()=> {
console.log('hello world')
}
export default fn
index.ets:
// 路径: 查找文件时,从起点到终点的路线
// 相对路径:从当前文件出发查找目标文件
// -> 找上一级 ../
// -> 找同级目录 ./
import num from '../tools/module1'
import fn from '../tools/module2'
console.log('module1 中的数据:', JSON.stringify(num))
// 函数
fn()
3、按需导入和导出
按需导出:指的是一个模块,可以按照需要,导出多个特性。
export {name1, name2, ..., nameN};
import {name1, name2, name3 as 别名} from "module-name"
module3.ets:
// 按需导出
// 多个特性,逐个 export 按需导出
let name1: string = '刘备'
let price: number = 9.98
let sayHi = () => {
console.log('打招呼啊')
}
// 一次性将对各特性,进行导出
export {name1, price, sayHi}
index.ets: 部分代码
// 按需导入
import {name1, price, sayHi as sayHello} from '../tools/module3'
console.log('module1 中的数据:', JSON.stringify(num))
// 函数
fn()
console.log('module3中的数据:', name1, price)
sayHello()
4、全部导入
export {name1, name2, ...}
import * as Module3 from '../tools/module3'
console.log('全部的数据', Module3.name1)