[TOC]
**编程思想:** 面向对象、面向过程、函数式编程
**面向对象是一种编程思想。(切入点)**
**面向对象:** Oriented (基于) Object (事物) , 简称:OO
是一种编程思想,它提出一切以对象对切入点思考问题。
- JS没有类型检查,如果使用面向对象的方式开发,会产生大量的接口,这会导致调佣复杂度剧增。
所以必须通过严格的类型检查来避免错误。尽管可以使用注解、文档甚至是记忆力,但是它们没有强约束力。
- TS带来了完整的类型系统。在开发复杂项目时,都可以获得完整的类型检查。并且这种检查是据有强约束力的。
对象继承规则:子类成员不能改变父类成员的属性类型
**设计模式:** 面对一些常见的功能场景,有一套固定、经过多年实践、且非常成熟的方式处理这些问题,这种方法被称之为设计模式。
## :-: 抽象类
```
// 模版模式:有些方法所有的子类实现的流程完全一致,只是流程中的某个步骤(规则)具体实现不一致。可以将该方法提取到父类,在父类中完成整个流程的实现。
// abstract -- 抽象类(对象不能单独创建,只能被继承)
// 抽象类:只表示一个抽象概念,主要用于提取子类共有的成员,而不能直接创建它的对象。
abstract class A {
// readonly -- 被修饰的字段为只读类型,不可修改
// public -- 公开的(默认),所有代码均可访问。
// protected -- 受保护的成员,只能在自身和子类中访问。
// private -- 私有的,只能在自身访问,继承的子类无法访问。
protected a: number = 1;
x: number = 0;
y: number = 0;
// abstract -- 抽象成员,必须出现在抽象类中。这些抽象成员必须在子类中实现。
// 父级中,可能知道有些成员是必须存在的,但是不知道该成员的值或实现是什么。因此需要强约束,让继承该类的子类必须实现这个成员(属性/方法)。
abstract name: string; // 定义抽象成员 (子类必须实现)
abstract rule(targetX: number, targetY: number): boolean; // 定义抽象方法 (子类必须实现这个方法)
// 模版模式:有些方法所有的子类实现的流程完全一致,只是流程中的某个步骤(规则)具体实现不一致。
// 可以将该方法提取到父类,在父类中完成整个流程的实现。遇到实现不一致的方法时,将该方法做成抽象方法。
move(targetX: number, targetY: number): boolean {
console.log("1.边界判断");
console.log("2.目标位置是否有乙方棋子");
// - 3.棋子移动规则判断
if (this.rule(targetX, targetY)) {
this.x=targetX; this.y=targetY;
return true;
}
return false;
}
}
class B extends A {
// 假设rule是象棋的规则函数
rule(targetX: number, targetY: number): boolean {
console.log("- 3.棋子移动规则判断");
return true;
}
name = "马"; // 父级定义了'抽象成员',子级必须要处理它,给予该属性赋值。
e?: string = null;
// super -- 读取父类资源,调用父类的属性/方法
// super.b
}
new B().move(5, 5);
// const a = new A(); // 已经定义了抽象类,将无法创建抽象类的实例。
const b: A = new B(); // 鸭子辩型
if (b instanceof B) { // 触发类型保护
b.e = undefined; }
```
```
export interface IFireShow {
name: string;
}
// 抽象类
export abstract class Animal {}
// 子类 (必须实现IFireShow的接口)
export class Lion extends Animal implements IFireShow {
name = "xxx";
}
// 类型保护函数:通过调用该函数,会触发TS的类型保护,该函数必须返回 Boolean
function hasShow(ani: object): ani is IFireShow {
if ((ani as IFireShow).name) {
return true;
}
return false;
}
// 接口可以继承自类(class)
// interface C extends Aobj,Bobj { }
```
## :-: 静态成员
```
// 实例成员:属于某个类的对象。'new User().log()'
// 静态成员(static):属于某个类。'User.login()'
class User {
static Users: User[] = [];
constructor(public name: string, public pwd: string) {
User.Users.push(this);
}
// 定义静态方法
static login(name: string, pwd: string): User | undefined {
return User.Users.find(u => name === u.name && pwd === u.pwd);
}
log() { console.log(this.name, this.pwd); }
}
const u1 = new User("name_111", "pwd_111");
const u2 = new User("name_222", "pwd_222");
console.log(User.Users);
console.log(User.login("name_111", "pwd_111"));
```
## :-: 设计模式-单例模式
```
// 所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。
class Board {
width: number = 500;
height: number = 700;
init() { console.log("初始化棋盘"); }
private constructor() {} // 让外部无法通过new的方式创建
private static _board?: Board;
static createBoard(): Board {
return this._board ? this._board : (this._board = new Board());
}
}
// new Board(); 此时构造函数是私有的,外部无法创建对象
Board.createBoard(); // 只会创建一次,无论被调用多少次都返回一样的结果。
```
## :-: 索引器
```
// 可以开启'noImplicitAny'配置对隐式any进行检查
class User1 {
[prop: string]: string | boolean; // 对所有成员进行类型限制
name = "xxx";
}
new User1()[0] = true;
```
## :-: this指向约束
```
// 使用bind、apply、call可以手动绑定this对象。
// 配置'noImplicitThis'为true,表示不允许this隐式的指向any
interface u {
name:string; age:number;
sayHello(this:u): void; // 手动声明该函数中this的指向。
}
const user2:u = {
name:"xxx", age:18,
// sayHello(this:u) { ··· }
sayHello() { console.log(this.name, this.age); }
};
user2.sayHello();
// const fun=user2.sayHello;fun(); // 已经声明约束了this指向,这种方式调用会报错
```
## :-: 装饰器
### 概述
> - 面向对象的概念(java:注解、C#:特征),decorator
> - 在`Angular`中大量使用,`React`中也有用到。
> - 目前 js 支持装饰器,但是还没有正式成为标准。(目前处于建议征集的第二阶段)
### 解决的问题
> - 装饰器,分离关注点。
> - 装饰器的本质是一个函数,用于修饰 类、属性、参数
*****
> `Object.getPrototypeOf(Obj).constructor.name`
> 得到一个对象的原型 --> 构造函数 --> 定义的名 (User)
*****
### :-: 类装饰器
```ts
// function test(target: Function) {}
// 在ts中约束一个构造函数 Function | new()=>object
function test(target: new (...args: any[]) => object) {
// target -- 是类(A)
new A();
}
@test
class A { ··· }
```
### :-: 成员装饰器
```ts
// 属性 -- 属性装饰器也是一个函数,该函数提供两个参数
// 1.如果是静态属性,则为类本身。如果是实例属性,则为类的原型
// 2.固定为属性名
// 方法 -- 方法装饰器也是一个函数,该函数提供三个参数
// 1.如果是静态属性,则为类本身。如果是实例方法,则为类的原型
// 2.固定为属性名
// 3.属性描述对象
function enumerable(target: any, key: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = true; // 让方法也可以被枚举
}
class B {
@enumerable
xxxxx() { /* ··· */ }
}
```
### :-: 推荐库
- reflect-metadata -- 它专门用于维护类、属性的元数据
```ts
import "reflect-metadata"; // 库是全局的只需导入一次,不返回任何变量
const key = Symbol.for("descriptor"); // 绝对唯一
export function descriptor(description: string) {
return Reflect.metadata(key, description);
}
export function printObj(obj: any) {
const cons = Object.getPrototypeOf(obj);
if (Reflect.hasMetadata(key, cons)) {
console.log(Reflect.getMetadata(key, cons));
} else {
console.log(cons.constructor.name);
}
// 输出所有的属性描述和属性值
for (const k in obj) {
if (Reflect.hasMetadata(key, obj, k)) {
console.log(`\t${Reflect.getMetadata(key, obj, k)} : ${obj[k]}`);
} else {
console.log(`\t${k} : ${obj[k]}`);
}
}
}
// 第三方库:reflect-metadata -- 它专门用于维护类、属性的元数据
import { descriptor, printObj } from "./Descriptor";
@descriptor("文章")
class Article {
@descriptor("标题")
title = "这是文章标题";
@descriptor("内容")
content = "这是文章的内容";
@descriptor("时间")
date = new Date();
}
const article = new Article();
printObj(article);
/*
* Article
* 标题 : 这是文章标题
* 内容 : 这是文章的内容
* 时间 : Sat Mar 28 2020 14:53:55 GMT+0800 (GMT+08:00)
*/
```
- class-validator -- 属性装饰器,数据验证
```ts
import { IsNotEmpty, validate, MinLength, MaxLength, Max, Min } from "class-validator";
import { Type } from "class-transformer";
class RegUser {
@IsNotEmpty({ message: "帐号不能为空!" }) // 非空校验
loginId!: string;
@IsNotEmpty({ message: "密码不能为空!" })
@MinLength(6, { message: "密码不能小于6个字符!" })
@MaxLength(16, { message: "密码不能大于16个字符!" })
loginPwd!: string;
@Max(100, { message: "年龄必须小于100" })
@Min(0, { message: "年龄必须大于0" })
@Type(() => Number) // 一般用于将`axios`请求过来的数据中为string类型的字段,转换为number类型。"123" -> 123
age!: number;
gender!: "男" | "女";
}
const post = new RegUser();
post.loginId = "id_xxx";
// post.loginPwd = "pwd_xxx";
post.age = -10;
validate(post).then(errors => { // 验证方法是异步执行的
console.log(errors);
/*
* [
* ValidationError {
* target: RegUser { loginId: 'id_xxx', age: -10 }, -- 验证哪个实例
* value: undefined, -- 赋的值是什么
* property: 'loginPwd', -- 属性名
* children: [],
* constraints: { -- 没有实现的约束
* maxLength: '密码不能大于16个字符!',
* minLength: '密码不能小于6个字符!',
* isNotEmpty: '密码不能为空!'
* }
* },
* ValidationError {
* target: RegUser { loginId: 'id_xxx', age: -10 },
* value: -10,
* property: 'age',
* children: [],
* constraints: { min: '年龄必须大于0' }
* }
* ]
*/
});
```
- class-transformer -- 将平面对象转换成类的对象。
### 补充
- 参数装饰器(依赖注入、依赖倒置)
- 关于 ts 自动注入
- 面向对象 `AOP`
## :-: 类型演算
- `typeof` -- 当作用于类的时候,得到的类型,是该类的构造函数。
- `keyof` -- 作用于 类、接口、类型别名,用于获取其他类型中的所有成员名组成的联合类型。`const abc:keyof User;`
- `in` -- 该关键字往往和 keyof 联用,用于限制某个索引的取值范围。
- `type UserString = { [key in 'loginId' | 'loginPwd' | 'age']:string }`
- `type UserString = { [key in keyof User]:string }`
- `type UserReadonly = { readonly [key in keyof User]?:User[key] }`
- `type Partial<T> = { readonly [key in keyof T]?:T[key] }` -> `const u:Partial<User> = { ··· }`
### TS自带的类型演算
```ts
Required<T> -- 将类型T中的成员变为必须
Readonly<T> -- 将类型T中的成员变为只读
Exclude<T,U> -- 从T中移除可以赋值给U的类型
Extract<T,U> -- 相反,提取T中可以赋值给U的类型
NonNullable<T> -- 从T中移除 null 和 undefined
ReturnType<T> -- 获取函数返回值的类型
InstanceType<T> -- 获取构造函数类型的实例类型
```
## :-: 声明文件
### 概述
- 创建一个以`.d.ts`结尾的文件
- 其作用是为普通的 js 代码文件提供类型声明
- 声明文件的位置
- 放置到 `tsconfig.json` 配置中包含的目录中
- 放置到 `node_modules/@types` 文件夹中
- 手动配置
- 与 js 代码所在的目录相同,并且文件名也相同的文件,用 ts 代码书写的工程发布之后的格式,(推荐)
### 编写
- 手动编写
- 自动生成 -- 工程是使用 ts 开发的,配置`declaration`为`true`即可。
- 前端工具库
- HTML
- CSS
- 实用样式
- JavaScript
- 模拟运动
- 深入数组扩展
- JavaScript_补充
- jQuery
- 自定义插件
- 网络 · 后端请求
- css3.0 - 2019-2-28
- 选择器
- 边界样式
- text 字体系列
- 盒子模型
- 动图效果
- 其他
- less - 用法
- scss - 用法 2019-9-26
- HTML5 - 2019-3-21
- canvas - 画布
- SVG - 矢量图
- 多媒体类
- H5 - 其他
- webpack - 自动化构建
- webpack - 起步
- webpack -- 环境配置
- gulp
- ES6 - 2019-4-21
- HTML5补充 - 2019-6-30
- 微信小程序 2019-7-8
- 全局配置
- 页面配置
- 组件生命周期
- 自定义组件 - 2019-7-14
- Git 基本操作 - 2019-7-16
- vue框架 - 2019-7-17
- 基本使用 - 2019-7-18
- 自定义功能 - 2019-7-20
- 自定义组件 - 2019-7-22
- 脚手架的使用 - 2019-7-25
- vue - 终端常用命令
- Vue Router - 路由 (基础)
- Vue Router - 路由 (高级)
- 路由插件配置 - 2019-7-29
- 路由 - 一个实例
- VUEX_数据仓库 - 2019-8-2
- Vue CLI 项目配置 - 2019-8-5
- 单元测试 - 2019-8-6
- 挂载全局组件 - 2019-11-14
- React框架
- React基本使用
- React - 组件化 2019-8-25
- React - 组件间交互 2019-8-26
- React - setState 2019-11-19
- React - slot 2019-11-19
- React - 生命周期 2019-8-26
- props属性校验 2019-11-26
- React - 路由 2019-8-28
- React - ref 2019-11-26
- React - Context 2019-11-27
- PureComponent - 性能优化 2019-11-27
- Render Props VS HOC 2019-11-27
- Portals - 插槽 2019-11-28
- React - Event 2019-11-29
- React - 渲染原理 2019-11-29
- Node.js
- 模块收纳
- dome
- nodejs - tsconfig.json
- TypeScript - 2020-3-5
- TypeScript - 基础 2020-3-6
- TypeScript - 进阶 2020-3-9
- Ordinary小助手
- uni-app
- 高德地图api
- mysql
- EVENTS
- 笔记
- 关于小程序工具方法封装
- Tool/basics
- Tool/web
- parsedUrl
- request