[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