TypeScript面向对象编程
SOLID(下面的首字母简写)原则
- 职责单一原则(SRP):组件(函数、类、模块)专注于单一任务,这样容易看出类做了哪些事情。类的属性通常描述对象的特征,方法通常描述对象行为。如果拥有过多属性和方法,就要考虑是否职责单一(比如Person类有名字、性别、电话、说hello的方法。那么验证电话号码正确性的方法,应该抽成另外一个类里。)
- 开/闭原则(OCP):时刻考虑到代码的扩展性(就是新增功能时候,能够最小程度修改代码)
- 里氏替换原则(LSP):派生类对象替换基类对象(比如b是基类有个save方法,a是派生类可以有自己的save方法)
- 接口隔离原则(ISP):将特别大的接口,拆分成小的。
- 依赖反转原则(DIP):一个方法遵从依赖于抽象而不是实例。
新建项目
1 | npm init |
目录结构,这里选择了比较熟悉的gulp
,而没使用webpack
。
1 | ├── gulpfile.js |
tsconfig.json
1 | 可以通过这种方式创建 |
1 | { |
gulpfile.js
1 | const gulp = require("gulp"); |
main.ts
1 | class Test { |
编译一下试试
1 | npx gulp |
编译出来文件在dist/main.js
1 | var Test = /** @class */ (function () { |
装饰器
装饰器有类装饰器
、参数装饰器
、方法装饰器
和属性装饰器
。它们的作用就是在不修改原有对象(接口)的情况下,对类及其方法、入参、属性行为的修改。
类装饰器
main.ts
1 | function logClass(target: any) { |
遇到提示
解决方案,修改tsconfig.json
文件:
1 | { |
编译ts,main.js文件:
1 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
类装饰器接收一个参数(构造函数),为类添加一些额外的逻辑。
方法装饰器·
main.ts
1 | function logMethod(target: any, key: string, descriptor: any) { |
main.js
1 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
方法装饰器接收3个参数,属性对象,属性名和属性描述符,为方法增加一些额外的逻辑。
属性装饰器
main.ts
1 | function logProperty(target: any, key: string) { |
main.js
1 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
属性装饰器接收2个参数,属性对象与属性名,为属性的set和get操作添加一些逻辑
参数装饰器
main.ts
1 | function addMetadata(target: any, key: string, index: number) { |
main.js
1 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
装饰器工厂
装饰器工厂能够鉴别使用哪种装饰器
使用@log
装饰器
带参装饰器
特殊的装饰器工厂
1 | function logMethod(options: any) { |
装饰器补充
1 | function withAuth(url: string) { |
我们通过编译后的代码,看一下 new A() 之后发生了什么
1 | var __extends = (this && this.__extends) || (function () { |
新语法
declare var
声明全局变量
declare function
声明全局方法
declare class
声明全局类
declare enum
声明全局枚举类型
declare namespace
声明(含有子属性的)全局对象
interface
和 type
声明全局类型
export
导出变量
export namespace
导出(含有子属性的)对象
export default
ES6 默认导出
export =
commonjs 导出模块
export as namespace
UMD 库声明全局变量
declare global
扩展全局变量
declare module
扩展模块
/// <reference />
三斜线指令
全局变量的声明文件主要有以下几种语法:
declare var
声明全局变量
用来定义一个全局变量的类型
1 | declare var functionA: (param: any) => any; |
declare function
声明全局方法
1 | declare function functionA(selector: string): any; |
declare class
声明全局类
1 | declare class Animal { |
declare enum
声明全局枚举类型
1 | declare enum Directions { |
declare namespace
声明(含有子属性的)全局对象
1 | declare namespace jQuery { |
- namespace 添加命名空间
1 | namespace Validation { |
reference
标签,告诉编译器文件之间的关系,当项目壮大的时候,可以用于分割多文件,下面的例子是分割了 Validation 命名空间到多文件。尽管文件被分割,但是还是在同一命名空间下
Validation.ts #
1 | namespace Validation { |
LettersOnlyValidator.ts #
1 | /// <reference path="Validation.ts" /> |
ZipCodeValidator.ts #
1 | /// <reference path="Validation.ts" /> |
Test.ts #
1 | /// <reference path="Validation.ts" /> |
使用 tsc 命令编译以上代码:
1 | tsc --out app.js test.ts |
得到 app.js
1 | /// <reference path="./valid.ts" /> |
运行 app.js
1 | node app.js |
1 | "Hello" - does not match ZIP code |
interface
和type
声明全局类型
1 | interface AjaxSettings { |
type
与 interface
类似
1 | type Name = string; |
声明语句中只能定义类型,不要在声明语句中定义具体实现。
声明文件
什么是.d.ts文件
这个文件是对第三方库类型API的类型声明,JavaScript
和TypeScript
能集成在一起依赖于它。
@types
使用 @types
统一管理第三方库的声明文件,可以使用npm
直接安装对应依赖包的声明模块
1 | npm install @types/jquery -S |
书写声明文件
不同场景下,声明文件的内容和使用方式也不同。
npm包
npm包的声明文件可能存在两个地方
package.json
中有types
字段,或者有一个index.d.ts
声明文件- 我们只需要尝试安装一下对应的
@types
包
如果没有描述文件,可以自己写声明文件
抽象类
abstract
用于定义抽象类和其中的抽象方法,它有以下特点
- 抽象类是不允许被实例化
- 抽象方法必须被子类实现
1 | abstract class Animal { |
看一下类的继承,使用 extends
关键字实现继承
1 | class Animal { |
Dog
类里没有构造函数,this
指向Dog
实例,看下编译成JavaScript
1 | var __extends = (this && this.__extends) || (function () { |
类的继承特点:
- 可以不需要实现父类的方法
- 可以使用
super
关键字来调用父类的构造函数和方法