3. 学习笔记:CSS选择器、继承与布局
本课程从TS基础入手,由基础类型一步步延伸到高级类型,通过示例来深入浅出的了解TypeScript的各种姿势。
TypeScript 和 JavaScript 的区别
TypeScript和JavaScript是两种编程语言,它们之间有一些重要的区别。下面是它们的主要区别:
-
静态类型 vs. 动态类型: JavaScript是一种动态类型语言,变量的类型在运行时才确定。而TypeScript是一种静态类型语言,变量的类型在编译时就要确定,并且在代码编写过程中需要显式地声明类型。
-
类型注解: 在TypeScript中,我们可以使用类型注解来明确变量的类型。这有助于提供更好的代码提示和类型检查,帮助开发者在编码阶段就发现潜在的类型错误。
-
编译过程: JavaScript是一种解释型语言,代码在运行前不需要编译。而TypeScript代码需要经过编译过程,将TypeScript代码转换为JavaScript代码,然后才能在浏览器或Node.js中运行。
-
ECMAScript标准支持: TypeScript是在ECMAScript标准之上的超集,它包含了所有JavaScript的特性,并且额外增加了静态类型系统和其他一些新特性。这意味着TypeScript可以无缝地使用JavaScript中的代码和库,并且还可以使用最新的ECMAScript特性。
-
开发工具支持: 由于TypeScript提供了更丰富的类型信息,开发工具(如IDE、编辑器等)可以提供更强大的代码提示、补全和错误检查功能,使得开发过程更高效。
-
适用场景: JavaScript适用于快速的Web开发和原型开发,特别适合在前端进行动态交互。而TypeScript适用于大型项目和需要更严格类型检查的场景,它可以帮助减少潜在的类型错误,提高代码的可维护性和可读性。
总体而言,JavaScript是一门非常灵活且广泛使用的语言,而TypeScript是JavaScript的增强版本,通过引入静态类型系统和其他特性,为大型项目提供了更好的结构和类型安全性。选择使用JavaScript还是TypeScript取决于项目的规模、复杂性和开发团队的偏好。
TypeScript基础
本部分将介绍TypeScript中的基础类型、函数类型、接口和类:
-
基础类型
TypeScript支持JavaScript的基础类型,如:number、string、boolean、null、undefined、symbol等。此外,TypeScript还增加了一些额外的类型,如:any、void、never、unknown等。 -
函数类型
在TypeScript中,可以为函数定义参数类型和返回值类型。例如:
function add(a: number, b: number): number {
return a + b;
}
这里的函数add接受两个参数a和b,都是number类型,并且返回值也是number类型。
-
接口 (interface)
接口是用于描述对象的形状的一种方式。通过接口,可以明确指定对象中应该包含哪些属性和它们的类型。例如:interface Person { name: string; age: number; } function greet(person: Person) { return `Hello, ${person.name}! You are ${person.age} years old.`; }这里定义了一个名为Person的接口,它包含name和age两个属性,然后在函数greet中使用该接口来约束参数person的类型。
-
类 (class)
TypeScript支持类的概念,可以使用class关键字来定义类。类可以具有属性和方法,并且可以使用构造函数初始化对象的属性。例如:class Animal { name: string; constructor(name: string) { this.name = name; } makeSound() { console.log("Animal makes a sound"); } } const dog = new Animal("Dog"); console.log(dog.name); // 输出 "Dog" dog.makeSound(); // 输出 "Animal makes a sound"这里定义了一个名为Animal的类,它有一个属性name和一个方法makeSound。使用构造函数创建一个名为dog的Animal实例,并调用makeSound方法。
4.1 访问修饰符 private、public 和 protected
在TypeScript类中,可以使用private、public和protected这三个访问修饰符来控制类成员的可见性和访问权限。
-
public
public是默认的访问修饰符,如果不指定访问修饰符,默认为public。使用public修饰的成员可以在类内部和类外部访问。class MyClass { public name: string; constructor(name: string) { this.name = name; } public sayHello() { console.log(`Hello, ${this.name}!`); } } const obj = new MyClass("John"); console.log(obj.name); // 输出 "John" obj.sayHello(); // 输出 "Hello, John!" -
private
private修饰符用于限制成员只能在类的内部访问,类的外部无法访问该成员。class MyClass { private age: number; constructor(age: number) { this.age = age; } public getAge() { return this.age; // 在类的内部可以访问私有成员 } } const obj = new MyClass(25); console.log(obj.getAge()); // 输出 25 console.log(obj.age); // 错误,age是私有成员,无法在类外部访问 -
protected
protected修饰符允许成员在类内部以及派生类中访问,但在类的外部是不可见的。class Parent { protected familyName: string; constructor(name: string) { this.familyName = name; } } class Child extends Parent { public getFullName() { return this.familyName + " Smith"; // 在派生类中可以访问 protected 成员 } } const child = new Child("John"); console.log(child.getFullName()); // 输出 "John Smith" console.log(child.familyName); // 错误,familyName是 protected 成员,无法在类外部访问
使用这些访问修饰符,可以控制类成员的可见性,从而增强类的封装性和安全性。根据需求选择合适的访问修饰符,是良好的编程实践。
4.2 抽象类和接口
在TypeScript中,抽象类和接口是两种不同的机制,用于对类进行约束和抽象。它们分别用于不同的场景:
-
抽象类(Abstract Class): 抽象类是用来作为其他类的基类的,它本身
不能被实例化。抽象类可以包含抽象方法(没有具体实现的方法)和具体方法(有具体实现的方法)。子类继承抽象类后,必须实现抽象方法。abstract class Animal { abstract makeSound(): void; move(): void { console.log("Animal is moving"); } } class Dog extends Animal { makeSound(): void { console.log("Dog barks"); } } const dog = new Dog(); dog.makeSound(); // 输出 "Dog barks" dog.move(); // 输出 "Animal is moving" -
接口(Interface): 接口是用来描述对象的形状的,它定义了对象应该具有哪些属性和方法。接口只能描述类的公共部分,不包含具体实现。
interface Person { name: string; age: number; sayHello(): void; } class Student implements Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } sayHello(): void { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); } } const student = new Student("John", 25); student.sayHello(); // 输出 "Hello, my name is John and I am 25 years old."接口可以用来约束类的结构,要求类必须包含接口中定义的属性和方法。
总结:
- 抽象类用于作为其他类的基类,并可以包含抽象方法和具体方法,需要被子类继承和实现抽象方法。
- 接口用于描述对象的形状,约束类必须包含接口中定义的属性和方法。一个类可以实现多个接口。
TypeScript进阶
TypeScript还包含很多其他功能,如泛型、枚举、命名空间等,以及一些高级的类型概念,包括联合类型、交叉类型、类型断言、类型别名和泛型。它们可以帮助我们更灵活地定义和使用类型。这些在大型项目中非常有用。通过引入类型检查和其他特性,TypeScript可以帮助开发者编写更健壮、可维护的代码。
-
联合类型(Union Types)
联合类型允许一个变量或参数具有多种可能的类型。使用竖线(|)分隔每个类型。let value: string | number; value = "hello"; // 合法 value = 42; // 合法 value = true; // 错误,布尔类型不是联合类型的其中一种 -
交叉类型(Intersection Types)
交叉类型将多个类型合并成一个类型,新类型具备所有原始类型的特性。type Point = { x: number; y: number }; type Color = { color: string }; type PointWithColor = Point & Color; const point: PointWithColor = { x: 10, y: 20, color: "red" }; -
类型断言(Type Assertion)
类型断言允许开发者在某些情况下手动指定变量的类型,告诉编译器变量的实际类型。使用尖括号语法或as关键字。let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; -
类型别名(Type Alias)
类型别名可以为类型起一个新名字,方便在多个地方复用复杂的类型定义。type UserID = string | number; type User = { id: UserID; name: string; }; -
泛型(Generics)
泛型允许在函数、类、接口等中使用类型参数,以便在使用时指定具体的类型。function identity<T>(arg: T): T { return arg; } const result = identity<number>(42);在上述例子中,
identity函数使用了泛型类型参数<T>,可以接受任意类型的参数并返回相同类型的值。 -
枚举(Enum)
在TypeScript中,枚举(Enum)是一种特殊的数据类型,用于为一组相关的常量赋予有意义的名字。枚举类型在JavaScript中并不存在,它是TypeScript为了增强代码可读性和可维护性而引入的概念。
使用枚举可以定义一组有序的常量,每个常量都有一个关联的名称和数值。以下是枚举的基本用法:
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
let dir: Direction = Direction.Up;
console.log(dir); // 输出 0
// 使用枚举值
if (dir === Direction.Up) {
console.log("向上");
} else if (dir === Direction.Down) {
console.log("向下");
} else if (dir === Direction.Left) {
console.log("向左");
} else if (dir === Direction.Right) {
console.log("向右");
}
在上述例子中,我们定义了一个名为Direction的枚举,它包含四个成员:Up、Down、Left和Right,分别对应数值0、1、2和3。然后我们创建一个名为dir的变量,它的类型是Direction,并将其赋值为Direction.Up,输出的结果为0,因为Up对应的数值是0。
枚举成员默认从0开始自增,也可以手动指定数值:
enum StatusCode {
OK = 200,
NotFound = 404,
ServerError = 500
}
此时,StatusCode.OK对应的数值是200,StatusCode.NotFound对应的数值是404,以此类推。
枚举还有一些其他特性,例如反向映射、枚举成员类型等。通过使用枚举,我们可以提高代码的可读性,使得一组相关的常量更加易于理解和维护。