学前班
TypeScript官网
JavaScript 与 TypeScript 的区别
TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。
TypeScript 的编译
TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
TypeScript 语法学习
输出日志
学习编程第一步,Hello World先输出!
console.log('Hello World!');
console.warn('Hello World!');
console.error('Hello World!');
变量
变量声明
TypeScript是JavaScript的超集,在JavaScript的基础上加入了静态类型检查功能,所以每一个变量都有固定的数据类型。
// msg 是变量名,string表示类型是字符串,等号右侧的东西会赋值给左侧的变量
let msg: string = 'Hello ArkTS'; // let 声明变量
const KEY: string = "key" // const 声明常量
// 在JS/TS中,使用'' "" 都可以表示字符串
// 语句结尾的 ; 可加可不加,最好是加上,你不加编译器也会帮你补充
数据类型
- string: 字符串,单引号双引号都可以
- number: 数值,整数、浮点数都可以
- boolean:布尔,true、fasle
- any: 不确定类型,可以是任意类型
- union:联合类型,可以是多个指定类型中的一种
- void:空类型,一般用于函数的返回值
- null:空对象
- undefined: 未定义,创建变量未赋值,或者对象没有这个变量但引用这个变量时的值
- Object :对象
- array:数组
- 元组
字符串类型
使用单引号('')或双引号("")来表示字符串,使用反引号(``)来定义多行字符串或内嵌表达式
let sa: string = '我学习,我进步!';
let ss: string = "加油自己,加油中国!";
let se: string =
`
我是第一行
我是第二行
我是第三行
`;
let sd = `${sa}${ss}`;
// 注意,string是小写
数字类型
双精度64位浮点数。可以用来表示整数和浮点数。TS中没有整数类型
let : number = 0b1010; // 二进制 0b
let octabinaryLiterallLiteral: number = 0o744; // 八进制 0o
let decLiteral: number = 6; // 十进制
let hexLiteral: number = 0xf00d; // 十六进制 0x
let floatLiteral: number = 0.98; // 浮点数
布尔
表示逻辑值:true 和 false。
let flag: boolean = true;
any 任意类型
因为any表示任意类型,所以给它赋值什么类型的数据都不犯毛病。意思也是告诉编译器,这个变量的类型不用你去给我推导,我想咋用咋用。但是这样做就让TypeScript失去了意义,那还不如用JavaScript了,费那劲写个any干啥。
let a:any = 'ArkUI';
a = 21;
a = true;
union 联合类型
变量赋值类型,可以是多个指定类型中的一种
let k: number|string|boolean = 'ItemAlign' // ✅
k = true; // ✅
k = 12;// ✅
k=[]; // ❌会报错:Type 'never[]' is not assignable to type 'string | number | boolean'.
void
变量有数据类型,函数同样有返回类型,void 用来表示函数没有任何返回值。
function hello(): void {
alert("Hello Bro!");
}
undefined
未定义,创建变量未赋值,或者对象中没有这个变量,但引用这个变量时的值
let a;
console.log(a); // undefined
console.log(b); // [ERR]: b is not defined
let c = {};
console.log(c.name); // undefined
Object
匿名对象,其实就是个Json,或者叫字典
//定义
let p = { name: "DaZui", age: 18 }
// 使用
p.name
p['name']
数组类型
数组的定义,有两种形式
// 1.在元素类型后面加上[]
let arr: number[] = [1, 2];
// 2.使用数组泛型
let arr: Array<number> = [1, 2];
// 使用
arr[0]; // 使用下标 访问数组元素
举例
let err : string[] = ["1",1] // 会报错,元素类型不一致
let arr : string[] = ["1","2"]; // ✅
let a = 1
let b = 'a'
let c : string[] = ["1",'1',`${a}${b}`] // c ["1", "1", "1a"],这个例子注意元素外的引号
元组
元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。
//定义
let d : [number,string];
d= [1,"2"]
//使用起来和数组一样,只是需要注意数据类型
d[0];
d[1];
条件控制
if
if else if esle
条件语句是嘎嘎常用的语句。
if(变量|表达式){
}else{
}
if(变量|表达式){
}else if(变量|表达式){
}else{
}
if 后面通常情况下会跟一个 boolean 类型的变量
let isSuccess: boolean = true;
if(isSuccess){
console.log('哇偶成功啦!');
}else{
console.log('哇去,失败了?');
}
当然,也可以跟一个返回值为boolean的表达式
let num:number = 2;
if(num % 2 === 0){
console.log(num+ '是偶数');
}else{
console.log(num+ '是奇数');
}
当然,还可以是一个返回值为boolean 的函数
function isSuccess():boolean {
return true;
}
if(isSuccess()){
console.log('哇偶成功啦!');
}else{
console.log('哇去,失败了?');
}
甚至,可以是任何你能想到的值
let a = 0;
let b = 1;
let c = '';
let d = "hh"
let e = {};
let f: number[] = [];
if(a || b || c || d || e || f){
console.log('哇偶成功啦!');
}else{
console.log('哇去,失败了?');
}
特别注意: 在TypeScript中,false、空字符串''、数字0、null、undefined,都被认为是false,其余值则为true
//所以if判断可以简写成这样
let num ;
if(num){
console.log('num有值');
}else{
console.log('num没有值');
}
switch-case
针对一个变量存在多种值进行判断时使用,switch()的参数一般情况下估计没人传boolean吧,彪呵的。
let grade : string = 'A';
switch(grade){
case 'A':{
console.log('真特么的好');
break;
}
case 'B' :{
console.log('一般好');
break;
}
case 'C':{
console.log('不咋地');
break;
}
default :{
console.log('胡说八道了');
}
}
循环迭代
循环迭代 for和while,应该所有语言都包含这两种循环语句
for
普通for循环
for(let i = 1 ; i < 10 ; i ++){
if(i == 5){
continue; // 跳过本次循环,继下次循环
}
if(i == 7){
break; // 直接跳出循环体
}
console.log(i);
}
console.log('循环执行完毕!');
for-in: 迭代index,即数组的角标
let arr: string[] = ["a","b","c"]
for(let i in arr){
console.log(i);
}
//输出 "0" "1" "2"
for-of: 迭代value,即数组的元素
let arr: string[] = ["a","b","c"]
for(let i of arr){
console.log(i);
}
// 输出 "a" "b" "c"
while
普通 while,但是一般这样的迭代会用 for
let j: number = 1;
while( j <= 10){
console.log(j);
j++;
}
while 常用场景
let isContinue : boolean = true;
while(isContinue){
if(当发生特定条件时){
isContinue = false;
}
}
函数
TypeScript通常使用function关键字声明函数,并且支持可选参数、默认参数、箭头函数等特殊语法。
函数通常用来封装可复用的操作,代码的可维护性更强。
函数的编写按照软件设计思想是有一定的要求的,要有明确的输入输出,不应该传递引用返回void,这样的函数可测性非常低。
无返回值,可以省略void,这样可读性会差一些,尽量不要这样做,养成好的编程习惯。
普通function
function sayHello(name: string): void{
console.log('你好,' + name + '!')
}
sayHello('Tom');
将function赋值给变量,因为function本身也是一种数据类型,它当然可以赋值给变量了。
let a = function(name: string): void{
console.log('你好,' + name + '!')
}
a('Bob');
自调用函数
let a = function (name: string): void{
console.log('你好,' + name + '!')
}('Jarry');
箭头函数
//完整写法
let a : (name:string) => void = (name: string):void =>{
console.log('你好,' + name + '!')
}
a('Tommy');
// 简写
let a = (name: string) => {
console.log('你好,' + name + '!')
}
a('Tommy');
可选参数函数
function sayHello(name?: string){
console.log('你好,' + name + '!')
}
sayHello(); // [LOG]: "你好,undefined!"
为参数添加默认值
(name: string = '陌生人')
// 添加默认值
function sayHello(name?: string){
name = name? name : '陌生人';
console.log('你好,' + name + '!')
}
sayHello();
//上面这种写法可以,但是很麻烦
function sayHello(name: string = '陌生人'){
console.log('你好,' + name + '!')
}
sayHello();
类和接口
TypeScript具备面向对象编程的基本语法,interface、class、enum等。同时也具备抽象、封装、继承、多态等面向对象的基本特征。
enum
enum是很常用的,可以明确定义边界,使程序降低出错的风险,同时也增强了扩展性,下面这种是很常见的不使用枚举的写法,每个地方都要考虑溢出的风险,后续想要增加一种类型,需要修改的地方就会很多,同时这些修改是不是覆盖的比较全面,也很不容易发现
// 不使用枚举时, 维护很困难
const RED: string = 'red';
const GREEN: string = 'green';
const BLUE: string = 'blue';
interface IPrintColor{
print(type: string): void; // 注意 type 是RED、GREEN、BLUE中的一个,使用时请注意判断越界
}
class Printer implements IPrintColor{
print(type: string) : void{
if(type !== RED && type !== GREEN && type !== BLUE){
console.log('ERR: 输入不合法,请重新输入!');
return;
}
console.log('颜色:' + type + '!')
}
}
比较好的实现方式
enum ColorType{
RED = '红色',
GREEN = '绿色',
BLUE = '蓝色'
}
interface IPrintColor{
print(type: ColorType): void;
}
class PrintColorZH implements IPrintColor{
print(type: ColorType) : void{
console.log('颜色:' + type + '!')
}
}
定义枚举, 使用关键字 enum, 如果不指定值,其值默认从0开始。
enum Type{
RED, // 0
GREEN, // 1
BLUE // 2
}
// 使用
Type.RED
console.log('颜色:' + Type.RED + '!'); // [LOG]: "颜色:0!"
可以为每一个元素指定一个value
enum What {
FOUR = 4,
FIVE = '5',
}
console.log('数字:' + What.FIVE + '!') // [LOG]: "数字:5!"
class
类的定义使用关键字 classs,constructor 用来定义构造函数,也就是创建对象时,为对象的成员变量进行初始化。使用 new 关键字来创建对象。
什么是类什么是对象呢? 比如 猫 就是类,TOM 就是 一个对象,是一个活生生存在的东西,而类呢,相当于一个模板,可以使用这个模板去创建一个真实存在的实体,这个实体就是对象。
class View{
private width: number ;
private height: number ;
// private index: number ; // 这一行会报错,定义时没有初始化,构造函数中又未定义
constructor(width: number, height: number){ // constructor 构造函数
this.width = width;
this.height = height;
}
changeWidth(newWidth : number){
this.width = newWidth;
}
logSelf(){
console.log(`width: ${this.width} , height: ${this.height}`); //
}
}
// 创建 View 类的 对象
let view : View = new View(100,200);
view.logSelf();
view.changeWidth(160);
view.logSelf();
说到类,当然要说到继承,继承使用关键字 extends 来实现。
// 定义矩形
class Rectangle{
private width: number ;
private height: number ;
// 构造函数
constructor(width: number, height: number){ // constructor 构造函数
this.width = width;
this.height = height;
}
//成员方法
public area() : number{
return this.width * this.height;
}
}
// 定义正方形
class Square extends Rectangle{
constructor(side: number){
// 调用父类构造函数
super(side, side);
}
}
let s = new Square(10);
console.log('正方形的面积为: ' + s.area()); // [LOG]: "正方形的面积为: 100"
interface
定义接口使用关键字 interface, 实现接口使用关键字 implements
接口就非常非常常用了,凡是学过面向对象编程语言的,都知道interface 在编程界的地位,通常我们说的callback其实也是基于interface去实现的。
interface CallBack{
onCall():void; // 声明方法,不需要有具体的实现,具体的实现由 类 来完成
}
class View{
callBack: CallBack;
constructor(callBack: CallBack){
this.callBack = callBack;
}
onClick(){
//干了一些事
this.callBack.onCall();
}
}
class ClickCallBack implements CallBack{
onCall(){
console.log('发生了点击')
}
}
let clickCallBack : ClickCallBack = new ClickCallBack();
let view = new View(clickCallBack);
view.onClick(); // [LOG]: "发生了点击"
比较全的案例:
enum ColorType{
RED = '红色',
GREEN = '绿色',
BLUE = '蓝色'
}
interface IPrintColor{
print(type: ColorType): void;
}
class PrintColorZH implements IPrintColor{
print(type: ColorType) : void{
console.log('颜色:' + type + '!')
}
}
class PrintColorEN implements IPrintColor{
print(type: ColorType) : void{
let printResult = '';
switch(type) {
case ColorType.RED: {
printResult = "Red"
break;
}
case ColorType.GREEN: {
printResult = "Green"
break;
}
case ColorType.BLUE: {
printResult = "Blue"
break;
}
}
console.log('This is :' + printResult + ' color!')
}
}
let myColorPrint: IPrintColor = new PrintColorZH(); // 创建了PrintColorZH但是由IPrintColor承接,这就是多态
myColorPrint.print(ColorType.BLUE); // [LOG]: "颜色:蓝色!"
myColorPrint = new PrintColorEN();
myColorPrint.print(ColorType.BLUE); // [LOG]: "This is :Blue color!"
模块
应用复杂时,把代码全放到一个文件是非常蠢的,读起来不方便,改起来更不方便。可以把一类通用功能抽取放到单独的ts文件中,每个文件都是一个模块(module)。模块可以互相加载,提高代码的复用性。维护起来也更轻松一些。
模块的导出使用export关键字。
模块的导入使用import from 关键字。
模块的定义与导出
// regtangle.ts文件中
export class Rectangle{
private width: number ;
private height: number ;
// 构造函数
constructor(width: number, height: number){ // constructor 构造函数
this.width = width;
this.height = height;
}
}
export function area(rec: Rectangle) : number{
return rec.width * rec.height;
}
模块的导入
// index.ts文件中
import { Rectangle , area} from '../regtangle'
let r = new Rectangle(10, 20);
console.log('长方形的面积为: ' + area(r)); // [LOG]: "长方形的面积为: 200"