├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── .gitignore ├── README.md ├── TS ├── Generics.md ├── Triple-SlashDirectives.md ├── advancedTypes.md ├── base.md ├── class.md ├── code │ ├── AT │ │ ├── at.1.ts │ │ ├── at.2.ts │ │ ├── at.3.ts │ │ └── at.4.ts │ ├── class │ │ ├── class.1.ts │ │ ├── class.2.ts │ │ ├── class.3.ts │ │ ├── class.4.ts │ │ ├── class.5.ts │ │ ├── class.6.ts │ │ ├── class.7.ts │ │ ├── class.8.ts │ │ └── class.9.ts │ ├── decorators │ │ ├── decorators.1.js │ │ ├── decorators.1.ts │ │ ├── decorators.2-1.js │ │ ├── decorators.2-1.ts │ │ ├── decorators.2.js │ │ ├── decorators.2.ts │ │ ├── decorators.3.js │ │ ├── decorators.3.ts │ │ ├── decorators.4.js │ │ ├── decorators.4.ts │ │ ├── decorators.5.js │ │ ├── decorators.5.js.map │ │ ├── decorators.5.ts │ │ └── readme.md │ ├── fileTypeChecking │ │ ├── ftc.1.js │ │ └── ftc.1.ts.js │ ├── generics │ │ ├── generics.1.ts │ │ └── generics.2.ts │ ├── interface │ │ ├── interface.1.ts │ │ ├── interface.2.ts │ │ └── interface.3.ts │ ├── module │ │ ├── demo │ │ │ ├── LettersOnlyValidator.ts │ │ │ ├── StringValidator.ts │ │ │ ├── ZipCodeValidator.ts │ │ │ ├── build │ │ │ │ ├── LettersOnlyValidator.js │ │ │ │ ├── StringValidator.js │ │ │ │ ├── ZipCodeValidator.js │ │ │ │ └── main.js │ │ │ └── main.ts │ │ ├── module_export.1.ts │ │ └── module_import.1.ts │ ├── namespace │ │ ├── namespace.1.js │ │ ├── namespace.1.ts │ │ ├── namespace.2.ts │ │ └── namespace.3.ts │ ├── package-lock.json │ ├── package.json │ ├── polymorphism │ │ ├── build │ │ │ ├── Animal │ │ │ │ ├── Animal.abs.js │ │ │ │ ├── Animal.interface.js │ │ │ │ ├── Animal_abs.js │ │ │ │ ├── Animal_interface.js │ │ │ │ ├── Cat.js │ │ │ │ └── Dog.js │ │ │ ├── Breeder.js │ │ │ ├── Food │ │ │ │ ├── Bone.js │ │ │ │ ├── DogFood.js │ │ │ │ ├── DogFood_interface.js │ │ │ │ ├── Fish.js │ │ │ │ ├── Food.abs.js │ │ │ │ ├── Food.interface.js │ │ │ │ ├── Food_abs.js │ │ │ │ └── Food_interface.js │ │ │ ├── Tool.js │ │ │ └── main.js │ │ ├── package.json │ │ ├── readme.md │ │ ├── src │ │ │ ├── Animal │ │ │ │ ├── Animal_abs.ts │ │ │ │ ├── Animal_interface.ts │ │ │ │ ├── Cat.ts │ │ │ │ └── Dog.ts │ │ │ ├── Breeder.ts │ │ │ ├── Food │ │ │ │ ├── Bone.ts │ │ │ │ ├── DogFood.ts │ │ │ │ ├── Fish.ts │ │ │ │ ├── Food_abs.ts │ │ │ │ └── Food_interface.ts │ │ │ ├── Tool.ts │ │ │ └── main.ts │ │ └── tsconfig.json │ ├── service │ │ ├── package.json │ │ ├── src │ │ │ └── main.ts │ │ └── tsconfig.json │ ├── tsconfig.json │ ├── tsconfig │ │ └── tsconfig.json │ └── update │ │ ├── update2.7 │ │ ├── update.1.js │ │ ├── update.1.ts │ │ └── update.2.ts │ │ └── update2.8 │ │ └── update.1.ts ├── d.ts.md ├── decorators.md ├── fileTypeChecking.md ├── function.md ├── interface.md ├── jsx.md ├── mixins.md ├── modifier.md ├── module.md ├── moduleResolution.md ├── namespace.md ├── readme.md ├── tsconfig.md └── update │ ├── readme.md │ ├── update-2.7-.md │ ├── update-2.7.md │ ├── update-2.8.md │ ├── update-2.9.md │ ├── update-3.0.md │ └── update-3.1.md ├── algorithm └── leecode │ ├── lee1.js │ ├── lee118.js │ ├── lee119.js │ ├── lee136.js │ ├── lee14.js │ ├── lee169.js │ ├── lee189.js │ ├── lee190.js │ ├── lee191.js │ ├── lee2.js │ ├── lee231.js │ ├── lee258.js │ ├── lee268.js │ ├── lee27.js │ ├── lee28.js │ ├── lee326.js │ ├── lee35.js │ ├── lee371.js │ ├── lee389.js │ ├── lee461.js │ ├── lee485.js │ ├── lee560.js │ ├── lee605.js │ ├── lee657.js │ ├── lee7.js │ ├── lee709.js │ ├── lee728.js │ ├── lee771.js │ ├── lee896.js │ ├── lee9.js │ ├── lee905.js │ ├── lee929.js │ ├── package.json │ ├── readme.md │ ├── shell.js │ └── yarn.lock ├── design └── pattern │ ├── readme.md │ └── singleton │ ├── readme.md │ └── singleton.ts ├── dev.md ├── env └── index.md ├── interesting ├── excellentBlog.md ├── hehe.js ├── hehe.md ├── in1.md ├── in2.md ├── in3.md ├── in4.md └── in5.md ├── js └── syncAndAsync │ ├── callback │ ├── lib │ │ ├── cb-ctrlreceive.js │ │ └── cb-ctrlsend.js │ ├── readme.md │ └── readme.old.md │ ├── cpsThunk │ ├── code │ │ ├── thunk.1.js │ │ └── thunk.2.js │ └── readme.md │ └── generator │ ├── code │ ├── generator.1.ts │ ├── generator.2.ts │ └── generator.3.ts │ └── readme.md ├── resource ├── bg.png └── img │ ├── ToObject.png │ ├── base.1.png │ ├── generator.1.png │ ├── hehe │ ├── h1.png │ ├── h10.png │ ├── h11.png │ ├── h2.png │ ├── h3.png │ ├── h4.png │ ├── h5.png │ ├── h6.png │ ├── h7.png │ ├── h8.png │ └── h9.png │ ├── jsx.1.png │ ├── lee258.jpeg │ ├── middleware.gif │ ├── operate.png │ ├── toNumber.png │ └── wk.png └── source ├── Lodash ├── Lodash-4.17.10.md ├── Lodash-4.17.10 │ ├── p1-variable.md │ ├── p2-top-method.md │ ├── p3-Built-in-references.md │ └── runInContext-main.md ├── demo │ └── lodash-this.js ├── lodash.js └── readme.md ├── Underscore.js ├── demo │ ├── is-fun.js │ └── noConflict.js ├── readme.md ├── underscoreJs-0.5.0.md ├── underscoreJs-1.5.0.md ├── underscoreJs-1.9.0.md └── underscoreJs-1.9.0 │ ├── Array-function.md │ ├── Collection-function.md │ ├── Function-function.md │ ├── Object-function.md │ └── Utility-function.md ├── delegates ├── index.js └── readme.md └── koa2 ├── code ├── koa.zip ├── koa │ ├── app.js │ ├── package.json │ ├── script │ │ └── custom-loader.mjs │ └── yarn.lock ├── onionRings.zip └── onionRings │ ├── callStack.js │ ├── koa-readFile.js │ ├── koa-readFile.ts │ ├── onionRings.js │ └── onionRings.ts ├── koa2 ├── lib │ ├── application.js │ ├── context.js │ ├── request.js │ └── response.js └── package.json ├── middleware └── readme.md └── readme.md /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: 获取用户信息 5 | labels: bug 6 | assignees: hooper-hc 7 | 8 | --- 9 | 10 | **bug 描述 / Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **截图 / Screenshots** 14 | If applicable, add screenshots to help explain your problem. 15 | 16 | **复现步骤 / To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | **预期结果 / Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: question 6 | assignees: hooper-hc 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 获取用户信息 5 | labels: enhancement 6 | assignees: hooper-hc 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | 40 | # mac 41 | .DS_Store 42 | 43 | 44 | # vscode 45 | .vs 46 | .vscode 47 | 48 | # TODO 49 | TODO* 50 | *todo* 51 | _git_* 52 | 53 | # debug 54 | *.js.map 55 | 56 | 57 | 58 | # 待删除 59 | 60 | algorithm/math/ 61 | algorithm/sort/ 62 | algorithm/Array/ 63 | deno/ 64 | engineering/ 65 | interview/ 66 | js/extends/ 67 | design/pattern/factory/ 68 | design/pattern/template.md 69 | design/thinking/ 70 | js/syncAndAsync/async-await/ 71 | js/syncAndAsync/csp/ 72 | js/syncAndAsync/promise/ 73 | js/syncAndAsync/thunk/ 74 | 75 | js/type/ 76 | node/ 77 | source/RXJS/ 78 | source/jquery/ 79 | source/Ramdajs/ 80 | source/co/ 81 | source/koa2/code/koa-router/ 82 | source/koa2/middleware/koa-router/ 83 | source/module/ 84 | source/reflect-metadata/ 85 | source/regenerator/ 86 | 87 | design/programming-paradigm/ 88 | -------------------------------------------------------------------------------- /TS/Generics.md: -------------------------------------------------------------------------------- 1 | # 泛型(Generics) 2 | 3 | > 延迟处理耦合逻辑 4 | 5 | 软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 6 | 7 | 不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。 8 | 9 | 1. 基础语法和使用 10 | 11 | - Q: 如果某个函数或者操作在定义时不能确定参数或者返回值的类型该怎么办? 12 | 13 | - A1: any 大法好。 14 | - A2: 干脆不写类型, 就好像没用过 TS 一样。 15 | - A3: 泛型。 16 | 17 | ```typescript 18 | function identity(arg: T): T { 19 | return arg; 20 | } 21 | // 泛型类型。 22 | let myIdentity: (arg: T) => T = identity; 23 | // 泛型并不是具体类型, 所以可以理解为类型占位, 还可以这么赋值 24 | let myIdentity: (arg: U) => U = identity; 25 | // 或者这么写, 实际上这个类型是一个接口的字面量 26 | let myIdentity: {(arg: T): T} = identity; 27 | 28 | // 接口泛型改进方案: 不再描述泛型函数,而是把非泛型函数签名作为泛型类型一部分 29 | interface GenericIdentityFn { 30 | (arg: T): T; 31 | } 32 | 实际上这也是非常漂亮的操作, 33 | let myIdentity: GenericIdentityFn = identity; 34 | ``` 35 | 36 | ```typescript 37 | // T 帮助我们捕获用户传入的类型 38 | function identity(len: T): T { 39 | // error: 类型“T”不可转换为类型“number”。 40 | // const P: any = len * len; 41 | 42 | // 事实上使用起来没有那么自在。很多类型不能断言到具体类型,不得不将其 any 化。 43 | // 其实与其转成 any 还不如使用 any 或者 直接不写类型。徒增复杂度。 44 | const P: any = len * len; 45 | return P; 46 | } 47 | 48 | // 明确的指定了T是string类型,并做为一个参数传给函数 49 | let iden = identity(10); 50 | // 第二种方法更普遍。利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型. 51 | // 官方说: 类型推论帮助我们保持代码精简和高可读性,「高可读性」 我不认同。 52 | iden = identity(10); 53 | ``` 54 | 上述代码存在一个很大的问题是: 我是用泛型定义函数后,函数体的实现却显得很不自由。简单的操作都有很多限制,考虑类型和转换等问题。 55 | 56 | 使用泛型创建像identity这样的泛型函数时,编译器要求你在函数体必须正确的使用这个通用的类型。 换句话说,你必须把这些参数当做是所有类型的联合类型。 57 | 58 | > 场景 59 | 60 | 实际上场景这个问题很重要,很多特性需要特定场景中处理会产生非常强大的效果, 泛型就是如此。 61 | 62 | 实际上我们上面栗子的问题在于,泛型本身是一种延迟获取的类型, 所以说如果泛型和具体的类型处理出现在同一个地方,则你不得不忙于处理各种可能的情况,或者取巧的将其转换成 any,不仅没有意义,还会得到一个很不合理的设计: 集抽象与具体于一身的操作,令人窒息。且看正确打开方式: 63 | 64 | ```typescript 65 | // 泛型和实现分离 66 | interface Animal { 67 | eat(T: T): U; 68 | } 69 | 70 | // 提供了具体类型然后去写逻辑则不用写出一堆毫无意义的代码。 71 | class Dog implements Animal { 72 | eat(food: Food): string { 73 | return food.name; 74 | } 75 | } 76 | 77 | class Food { 78 | constructor(public name: string) {} 79 | } 80 | 81 | const eatWhat = new Dog().eat(new Food('骨头')); 82 | 83 | console.log(eatWhat); 84 | ``` 85 | 86 | 同理利用函数和函数表达式也能实现函数面临的泛型问题。代码参考: [generics 1](./code/generics/generics.1.ts) 87 | 88 | 89 | 90 | 2. 在泛型里使用类类型 91 | 92 | 在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。比如 93 | ```typescript 94 | function create(c: {new(): T; }): T { 95 | return new c(); 96 | } 97 | ``` 98 | 99 | 100 | 3. 使用原型属性推断并约束构造函数与类实例的关系。 101 | 102 | 泛型约束: 103 | ```typescript 104 | interface Lengthwise { 105 | length: number; 106 | } 107 | 108 | function loggingIdentity(arg: T): T { 109 | console.log(arg.length); // Now we know it has a .length property, so no more error 110 | return arg; 111 | } 112 | ``` 113 | 114 | [generics 2](./code/generics/generics.2.ts) 115 | 116 | 117 | --- 118 | 119 | ## 注意 120 | 1. 泛型往往是在实例化或者调用时提供类型,所以静态方法不能够使用泛型类型。 121 | -------------------------------------------------------------------------------- /TS/Triple-SlashDirectives.md: -------------------------------------------------------------------------------- 1 | # 三斜线指令 2 | 3 | > 预编译指令: 三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。 4 | 5 | 三斜线指令仅可放在包含它的文件的最顶端。 一个三斜线指令的前面只能出现单行或多行注释,这包括其它的三斜线指令。 6 | 7 | 如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义。 8 | 9 | `/// ` 指令是三斜线指令中最常见的一种。 它用于声明文件间的 依赖。 10 | 11 | 三斜线引用告诉编译器在编译过程中要引入的额外的文件。 12 | 13 | 当使用--out或--outFile时,它也可以做为调整输出内容顺序的一种方法。 文件在输出文件内容中的位置与经过预处理后的输入顺序一致。 14 | 15 | 16 | --- 17 | 18 | [/// 指令](https://www.tslang.cn/docs/handbook/triple-slash-directives.html) 19 | -------------------------------------------------------------------------------- /TS/code/AT/at.1.ts: -------------------------------------------------------------------------------- 1 | namespace at1{ 2 | /** 3 | * 属性拷贝到一个对象 4 | * 5 | * @param first 6 | * @param second 7 | */ 8 | function extend(first: T, second: U): T & U { 9 | let result = {}; 10 | for (let id in first) { 11 | (result)[id] = (first)[id]; 12 | } 13 | for (let id in second) { 14 | if (!result.hasOwnProperty(id)) { 15 | (result)[id] = (second)[id]; 16 | } 17 | } 18 | return result; 19 | } 20 | 21 | class Person { 22 | constructor(public name: string) { } 23 | } 24 | interface Loggable { 25 | log(): void; 26 | } 27 | class ConsoleLogger implements Loggable { 28 | log() { 29 | // ... 30 | } 31 | } 32 | const jim = extend(new Person("Jim"), new ConsoleLogger()); 33 | const n = jim.name; 34 | jim.log(); 35 | } 36 | -------------------------------------------------------------------------------- /TS/code/AT/at.2.ts: -------------------------------------------------------------------------------- 1 | export namespace at2 { 2 | interface Bird { 3 | fly(); 4 | layEggs(); 5 | } 6 | 7 | interface Fish { 8 | swim(); 9 | layEggs(); 10 | } 11 | 12 | function getSmallPet(): Fish | Bird { 13 | return { 14 | fly() { }, 15 | swim() { }, 16 | layEggs() { } 17 | }; 18 | } 19 | 20 | let pet = getSmallPet(); 21 | 22 | pet.layEggs(); // okay 23 | pet.swim(); // errors 24 | } 25 | -------------------------------------------------------------------------------- /TS/code/AT/at.3.ts: -------------------------------------------------------------------------------- 1 | namespace at3 { 2 | class Bird { 3 | fly() { } 4 | layEggs() { } 5 | } 6 | 7 | class Fish { 8 | swim() { } 9 | layEggs() { } 10 | } 11 | 12 | function getSmallPet(): Fish | Bird { 13 | return new Fish(); 14 | } 15 | 16 | // common method 17 | let pet = getSmallPet(); 18 | pet.layEggs(); // okay 19 | // pet.swim(); // errors 类型“Bird | Fish”上不存在属性“swim”。 20 | 21 | 22 | // ----------------deal---------------- 23 | // 1. 类型断言 24 | if ((pet).swim) { 25 | (pet).swim(); 26 | } 27 | 28 | 29 | // 2. 类型谓词 30 | // pet is Fish就是类型谓词 31 | function isFish(pet: Fish | Bird): pet is Fish { 32 | return (pet).swim !== undefined; 33 | } 34 | if (isFish(pet)) { 35 | // 每当使用一些变量调用 isFish时,TypeScript会将变量缩减为那个具体的类型,只要这个类型与变量的原始类型是兼容的。 36 | pet.swim(); 37 | } else { 38 | pet.fly(); 39 | } 40 | 41 | 42 | // 3. 自动类型保护机制 43 | // instanceof 触发类型保护 44 | if (pet instanceof Fish) { 45 | // 类型细化为 Fish 46 | pet.swim(); 47 | } else { 48 | // 类型细化为 Bird 49 | pet.fly(); 50 | } 51 | } 52 | 53 | 54 | namespace at3_1{ 55 | /** 56 | * TS 自动识别的类型保护: typeof。 57 | * 满足如下条件会被识别为类型保护,不需要手动添加类型谓词判断 58 | * > typeof v === "typename" 59 | * > typeof v !== "typename", 60 | * > "typename"必须是 "number", "string", "boolean"或 "symbol"。 61 | * 62 | * TypeScript并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。 63 | */ 64 | 65 | function padLeft(value: number | string | boolean): number | string[] | boolean { 66 | // error: 算术操作数必须为类型 "any"、"number" 或枚举类型 67 | // value ++; 68 | 69 | // 类型保护 70 | if (typeof value === 'number') { 71 | return value ++; 72 | } else if (typeof value === 'string') { 73 | return value.split(''); 74 | } else { 75 | return !!value 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /TS/code/AT/at.4.ts: -------------------------------------------------------------------------------- 1 | namespace at4 { 2 | enum ShapeKind { square, rectangle, circle }; 3 | const { square, rectangle, circle } = ShapeKind; 4 | 5 | interface Square { 6 | kind: ShapeKind.square; 7 | size: number; 8 | } 9 | interface Rectangle { 10 | kind: ShapeKind.rectangle; 11 | width: number; 12 | height: number; 13 | } 14 | interface Circle { 15 | kind: ShapeKind.circle; 16 | radius: number; 17 | } 18 | 19 | // 类型别名 + 联合类型 20 | type Shape = Square | Rectangle | Circle; 21 | 22 | function area(s: Shape): number { 23 | switch (s.kind) { 24 | // kind 做辩识 25 | case square: return s.size * s.size; 26 | case rectangle: return s.height * s.width; 27 | case circle: return Math.PI * s.radius ** 2; 28 | default: return assertNever(s); 29 | } 30 | } 31 | 32 | // 这里有个小技巧,比如我们添加了一种新的图形,这时候我们讲 Shape 更新为: Shape = Square | Rectangle | Circle | othShape; 33 | // 但是忘记了更新 switch case 的话, 新的类型就会走到 default 进而触发 error 。 34 | function assertNever(x: T): never { 35 | throw new Error("Unexpected object: " + x); 36 | } 37 | 38 | const squareArea = area({ 39 | kind: square, 40 | size: 10 41 | }) 42 | const circleArea = area({ 43 | kind: circle, 44 | radius: 5 45 | }) 46 | 47 | console.log(squareArea, circleArea); 48 | } 49 | -------------------------------------------------------------------------------- /TS/code/class/class.1.ts: -------------------------------------------------------------------------------- 1 | namespace in1 { 2 | class Animal { 3 | name: string; 4 | constructor(theName: string) { this.name = theName; } 5 | move(distanceInMeters: number = 0) { 6 | console.log(`${this.name} moved ${distanceInMeters}m.`); 7 | } 8 | } 9 | 10 | class Snake extends Animal { 11 | constructor(name: string) { super(name); } 12 | move(distanceInMeters = 5) { 13 | console.log("Slithering..."); 14 | super.move(distanceInMeters); 15 | } 16 | } 17 | 18 | class Horse extends Animal { 19 | addr: string; 20 | constructor(name: string, addr?: string) { 21 | // super 不必再第一行,但是必须在 this 之前。 22 | addr = addr || 'china'; 23 | super(name); 24 | this.addr = addr; 25 | } 26 | // override 27 | move(distanceInMeters = 45) { 28 | console.log("Galloping..."); 29 | // super 可以在子类里随意使用。 30 | super.move(distanceInMeters); 31 | } 32 | } 33 | 34 | let sam = new Snake("Sammy the Python"); 35 | let tom: Animal = new Horse("Tommy the Palomino"); 36 | 37 | sam.move(); 38 | tom.move(34); 39 | } 40 | -------------------------------------------------------------------------------- /TS/code/class/class.2.ts: -------------------------------------------------------------------------------- 1 | class Animal { 2 | private name: string; 3 | constructor(theName: string) { this.name = theName; } 4 | } 5 | 6 | class Rhino extends Animal { 7 | constructor() { super("Rhino"); } 8 | } 9 | 10 | class Employee { 11 | private name: string; 12 | constructor(theName: string) { this.name = theName; } 13 | } 14 | 15 | let animal = new Animal("Goat"); 16 | let rhino = new Rhino(); 17 | let employee = new Employee("Bob"); 18 | 19 | animal = rhino; 20 | animal = employee; // 错误: Animal 与 Employee 不兼容(不能将类型“Employee”分配给类型“Animal”。类型具有私有属性“name”的单独声明。) 21 | -------------------------------------------------------------------------------- /TS/code/class/class.3.ts: -------------------------------------------------------------------------------- 1 | namespace AccessModifier1 { 2 | interface AData { 3 | a1: string; 4 | a2: string; 5 | a3: string; 6 | } 7 | 8 | class A { 9 | private a1: string; 10 | protected a2: string; 11 | public a3: string; 12 | 13 | constructor({ a1, a2, a3 }: AData = {}) { 14 | this.a1 = a1; 15 | this.a2 = a2; 16 | this.a3 = a3; 17 | } 18 | 19 | visit(): void { 20 | // 自身随意访问 21 | console.log(this.a1, this.a2, this.a3); 22 | } 23 | } 24 | 25 | class B extends A{ 26 | constructor(aData: AData) { 27 | super(aData); 28 | } 29 | 30 | childVisit(): void { 31 | // ERROR this.a1 : 子类可以访问 protected, 不可访问 private。 32 | console.log(this.a1, this.a2, this.a3); 33 | } 34 | } 35 | 36 | const aData = { 37 | a1: '1', 38 | a2: '2', 39 | a3: '3' 40 | }; 41 | const a = new A(aData); 42 | // error a.a1, a.a2: 外部访问: 只能访问 pbulic。 43 | console.log(a.a1); 44 | console.log(a.a2); 45 | console.log(a.a3); 46 | 47 | const b = new B(aData); 48 | // console.log(b.a1); 49 | // console.log(b.a2); 50 | console.log(b.a3); 51 | } 52 | 53 | 54 | namespace AccessModifier2 { 55 | // 构造器 + 访问修饰符 56 | class A { 57 | private constructor() { } 58 | // protected constructor() { } 59 | 60 | static Singleton(): A { 61 | // 可以在内部进行初始化 62 | return new A(); 63 | } 64 | 65 | desc() { 66 | console.log('singleton A..'); 67 | } 68 | } 69 | 70 | // error: 不可继承类: 无法扩展类“A”。类构造函数标记为私有。 71 | class B extends A { 72 | 73 | } 74 | 75 | // error: private, protected 构造不能再外部实例化。 类“A”的构造函数是私有的,仅可在类声明中访问。 76 | new A(); 77 | 78 | A.Singleton().desc(); 79 | } 80 | 81 | namespace AccessModifier3 { 82 | // 构造器 + 访问修饰符 83 | class A { 84 | protected constructor() { } 85 | 86 | static Singleton(): A { 87 | // 可以在内部进行初始化 88 | return new A(); 89 | } 90 | 91 | desc() { 92 | console.log('singleton A..'); 93 | } 94 | } 95 | 96 | // 可继承类 97 | class B extends A { 98 | des() { 99 | new A(); 100 | } 101 | } 102 | 103 | // error: protected 构造不能再外部实例化。 类“A”的构造函数是私有的,仅可在类声明中访问。 104 | new A(); 105 | A.Singleton().desc(); 106 | } 107 | -------------------------------------------------------------------------------- /TS/code/class/class.4.ts: -------------------------------------------------------------------------------- 1 | namespace getStateFormClass { 2 | class A { 3 | public a: string 4 | private a1: string; 5 | protected a2: string 6 | 7 | constructor(a, a1, a2) { 8 | this.a = a; 9 | this.a1 = a1; 10 | this.a2 = a2; 11 | } 12 | } 13 | 14 | class B extends A { 15 | constructor(a, a1, a2) { 16 | super(a, a1, a2) 17 | } 18 | } 19 | 20 | const b: B = new B('1', '2', '3'); 21 | 22 | // 尽管不能访问私有,保护的属性, 但是直接输出 b 还是能够得到完整的结构 23 | // B { a: "1", a1: "2", a2: "3" } 24 | console.log(b); 25 | 26 | //所以说还是能够拿到类的内部状态. 但是拿不到方法 27 | const cbs = JSON.parse(JSON.stringify(b)); 28 | console.log(cbs.a, cbs.a1, cbs.a2); 29 | } 30 | -------------------------------------------------------------------------------- /TS/code/class/class.5.ts: -------------------------------------------------------------------------------- 1 | namespace static { 2 | class Dog{ 3 | static legCount = 4; 4 | constructor(public name: string, private age: number) {} 5 | 6 | gatekeeper() { 7 | console.log(`${this.name}: go away!`); 8 | } 9 | 10 | static run() { 11 | // shift(没打错,梗)! 静态方法也能访问 this ? 这不是很好理解啊 12 | // 这里的 this 则是类本身,他和普通方法中的 this 是两个不同的上下文。一定要区分开。 13 | console.log(this === Dog); 14 | console.log(`running dog by ${this.legCount} legs`); 15 | console.log(`running dog by ${Dog.legCount} legs`); 16 | 17 | // 类型“typeof Dog”上不存在属性“age”。 18 | // console.log(this.age); 19 | } 20 | } 21 | 22 | Dog.run(); 23 | new Dog('dahuang', 4).gatekeeper(); // dahuang: wang! wang! 24 | } 25 | -------------------------------------------------------------------------------- /TS/code/class/class.6.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 静态成员也能继承, omg! 3 | */ 4 | namespace static { 5 | class A { 6 | static a = 1; 7 | private static b = 2; 8 | protected static c = 3; 9 | 10 | static f1() { 11 | this.f3(); 12 | } 13 | protected static f3() { 14 | this.f2(); 15 | } 16 | private static f2() { 17 | console.log(`(a: ${this.a}, b: ${this.b}, c: ${this.c})`); 18 | } 19 | } 20 | 21 | class B extends A {} 22 | 23 | console.log(B.a); 24 | // error Property 'b' is private and only accessible within class 'A'. 25 | // console.log(B.b); 26 | // console.log(B.c); 27 | 28 | B.f1(); 29 | // error 属性“f2”为私有属性,只能在类“A”中访问 30 | // B.f2(); 31 | // B.f3(); 32 | } 33 | -------------------------------------------------------------------------------- /TS/code/class/class.7.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 使用 typeof Greeter,意思是取Greeter类的类型,而不是实例的类型。 3 | * 或者更确切的说,"告诉我 Greeter标识符的类型",也就是构造函数的类型。 4 | * 这个类型包含了类的所有静态成员和构造函数。 5 | */ 6 | namespace constructorType{ 7 | class Greeter { 8 | static standardGreeting = "Hello, there"; 9 | greeting: string; 10 | greet() { 11 | if (this.greeting) { 12 | return "Hello, " + this.greeting; 13 | } 14 | else { 15 | return Greeter.standardGreeting; 16 | } 17 | } 18 | } 19 | 20 | let greeter1: Greeter = new Greeter(); 21 | Greeter.standardGreeting = 'cahnge default'; 22 | console.log(greeter1.greet()); // cahnge default 23 | 24 | console.log(typeof Greeter); // function 25 | 26 | let greeterMaker: typeof Greeter = Greeter; 27 | greeterMaker.standardGreeting = "Hey there!"; 28 | 29 | // 简单来说 greeterMaker 就是一个类类型, 通过类类型实例化一个类对象。 30 | // 类似反射的概念,但是 js 始终是函数式语言,函数式一等公民,所以这种情景下的反射并没有 java 中的反射给人感觉那么强大。 31 | // 因为我们可以直接修改 Greeter.standardGreeting。 32 | let greeter2: Greeter = new greeterMaker(); 33 | console.log(greeterMaker); // [Function: Greeter] 34 | console.log(greeter2.greet()); // Hey there! 35 | // 反射之后 standardGreeting 已经被改变。 36 | console.log(new Greeter().greet()); // Hey there! 37 | } 38 | -------------------------------------------------------------------------------- /TS/code/class/class.8.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 多态: 看名字就知道这部分有多吊了吧 3 | */ 4 | namespace extendType { 5 | class A { 6 | prop: string = 'A'; 7 | fn1(): void { 8 | console.log(this.prop); 9 | } 10 | } 11 | 12 | class B extends A { 13 | prop: string = 'B'; 14 | fn1(): void { 15 | console.log(this.prop); 16 | } 17 | fn2(): void { 18 | console.log(this.prop); 19 | } 20 | } 21 | 22 | const obj: A = new B(); 23 | /** 24 | * 讲子类实例赋值给父类类型,得到的对象以父类为规范,以子类实现为行为 25 | * 基本上就是多态的一个基本变现。 26 | * 实际上 obj 是 B 的实例,B 里声明了 fn2 函数, 但是 obj 却没法调用 27 | * 这个函数,因为承接 obj 的类型是 A, A 的声明里并没有 fn2. 28 | * 29 | * 利用这个特性,配合接口和抽象类基本上能够完成非常好的抽象约束能力。 30 | * 参考: /code/polymorphism/ 下的具体项目。 31 | */ 32 | obj.fn2(); // error Property 'fn2' does not exist on type 'A'. 33 | } 34 | -------------------------------------------------------------------------------- /TS/code/class/class.9.ts: -------------------------------------------------------------------------------- 1 | class A { 2 | p1: string = 'A'; 3 | fn1(): void {} 4 | } 5 | 6 | class B { 7 | p1: any = 1; 8 | fn1(): any {} 9 | fn2(): void {} 10 | } 11 | 12 | /** 13 | * 没有继承关系的多态。 14 | * TypeScript 使用的是结构性类型系统。 当我们比较两种不同的类型时,并不在乎它们从何处而来, 15 | * 如果所有成员的类型都是兼容的,我们就认为它们的类型是兼容的。 16 | */ 17 | const f: A = new B(); 18 | 19 | console.log(typeof f.p1); 20 | // error 21 | console.log(f.fn2); 22 | // right: 断言 23 | console.log((f).fn2); 24 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.1.js: -------------------------------------------------------------------------------- 1 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 2 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 3 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 4 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 5 | return c > 3 && r && Object.defineProperty(target, key, r), r; 6 | }; 7 | var decorators; 8 | (function (decorators) { 9 | function f() { 10 | console.log("f(): evaluated"); 11 | return function (target, propertyKey, descriptor) { 12 | console.log("f(): called"); 13 | }; 14 | } 15 | function g() { 16 | console.log("g(): evaluated"); 17 | return function (target, propertyKey, descriptor) { 18 | console.log("g(): called"); 19 | console.log(target, propertyKey, descriptor); 20 | }; 21 | } 22 | function h(target, propertyKey, descriptor) { 23 | console.log("h(): called"); 24 | } 25 | var C = /** @class */ (function () { 26 | function C() { 27 | } 28 | // 直接提供对应装饰器 29 | // - 由上至下依次对装饰器表达式求值。 30 | // - 求值的结果会被当作函数,由下至上依次调用。 31 | C.method = function (a, b) { 32 | console.log("method(): called"); 33 | }; 34 | __decorate([ 35 | h 36 | // 可传参 37 | , 38 | f(), 39 | g() 40 | ], C, "method", null); 41 | return C; 42 | }()); 43 | // f(g(method())); 44 | setTimeout(function () { 45 | // new C().method('C.method', 10); 46 | C.method('C.method', 10); 47 | }, 5000); 48 | })(decorators || (decorators = {})); 49 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.1.ts: -------------------------------------------------------------------------------- 1 | namespace decorators { 2 | function f(): (...param) => void { 3 | console.log("f(): evaluated"); 4 | return function (target, propertyKey: string, descriptor: PropertyDescriptor) { 5 | console.log("f(): called"); 6 | } 7 | } 8 | 9 | function g(): (...param) => void { 10 | console.log("g(): evaluated"); 11 | return function (target, propertyKey: string, descriptor: PropertyDescriptor) { 12 | console.log("g(): called"); 13 | console.log(target, propertyKey, descriptor); 14 | } 15 | } 16 | 17 | function h(target: Object, propertyKey: string, descriptor: PropertyDescriptor) { 18 | console.log("h(): called"); 19 | } 20 | 21 | class C { 22 | // 直接提供对应装饰器 23 | // - 由上至下依次对装饰器表达式求值。 24 | // - 求值的结果会被当作函数,由下至上依次调用。 25 | @h 26 | // 可传参 27 | @f() 28 | @g() 29 | // 可以切换到 static 测试静态成员 30 | // static method(a: string, b: number): void { 31 | method(a: string, b: number): void { 32 | console.log("method(): called"); 33 | } 34 | } 35 | 36 | // f(g(method())); 37 | 38 | setTimeout(() => { 39 | new C().method('C.method', 10); 40 | // C.method('C.method', 10); 41 | }, 5000); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.2-1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var decorators; 9 | (function (decorators) { 10 | function fnPlus(target, propertyKey, descriptor) { 11 | var oldFn = target[propertyKey]; 12 | descriptor.value = function () { 13 | var param = []; 14 | for (var _i = 0; _i < arguments.length; _i++) { 15 | param[_i] = arguments[_i]; 16 | } 17 | console.log.apply(console, ['before fn deal:'].concat(param)); 18 | var dealParam = oldFn.call.apply(oldFn, [target].concat(param)); 19 | console.log('after fn deal:', dealParam); 20 | }; 21 | } 22 | var Person = /** @class */ (function () { 23 | function Person() { 24 | } 25 | Person.prototype.fn = function (pa) { 26 | console.log('fn deal..'); 27 | return pa; 28 | }; 29 | __decorate([ 30 | fnPlus 31 | ], Person.prototype, "fn", null); 32 | return Person; 33 | }()); 34 | var lm = new Person(); 35 | lm.fn('fn'); 36 | })(decorators || (decorators = {})); 37 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.2-1.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace decorators { 3 | function fnPlus(target, propertyKey: string, descriptor: PropertyDescriptor) { 4 | const oldFn = target[propertyKey]; 5 | descriptor.value = (...param) => { 6 | console.log('before fn deal:', ...param); 7 | const dealParam = oldFn.call(target, ...param); 8 | console.log('after fn deal:', dealParam); 9 | } 10 | } 11 | 12 | class Person { 13 | @fnPlus 14 | fn(pa: string): string { 15 | console.log('fn deal..'); 16 | return pa; 17 | } 18 | } 19 | 20 | const lm = new Person(); 21 | lm.fn('fn'); 22 | } 23 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var decorators; 9 | (function (decorators) { 10 | function fnPlus(target, propertyKey, descriptor) { 11 | var oldFn = target[propertyKey]; 12 | target[propertyKey + '_plus'] = target[propertyKey] = function () { 13 | var param = []; 14 | for (var _i = 0; _i < arguments.length; _i++) { 15 | param[_i] = arguments[_i]; 16 | } 17 | console.log.apply(console, ['format param: '].concat(param)); 18 | var dealParam = oldFn.call.apply(oldFn, [target].concat(param)); 19 | console.log('deal result: ', dealParam); 20 | }; 21 | } 22 | var Person = /** @class */ (function () { 23 | function Person() { 24 | } 25 | Person.prototype.fn = function (pa) { 26 | console.log('fn call..'); 27 | return pa; 28 | }; 29 | __decorate([ 30 | fnPlus 31 | ], Person.prototype, "fn", null); 32 | return Person; 33 | }()); 34 | var lm = new Person(); 35 | lm.fn('fn'); 36 | console.log('----------'); 37 | // @ts-ignore 38 | lm.fn_plus('fn_plus'); 39 | })(decorators || (decorators = {})); 40 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.2.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace decorators { 3 | function fnPlus(target, propertyKey: string, descriptor: PropertyDescriptor) { 4 | const oldFn = target[propertyKey]; 5 | target[propertyKey + '_plus'] = target[propertyKey] = (...param) => { 6 | console.log('format param: ', ...param); 7 | const dealParam = oldFn.call(target, ...param); 8 | console.log('deal result: ', dealParam); 9 | } 10 | } 11 | 12 | class Person { 13 | @fnPlus 14 | fn(pa: string): string { 15 | console.log('fn call..'); 16 | return pa; 17 | } 18 | } 19 | 20 | const lm = new Person(); 21 | lm.fn('fn'); 22 | console.log('----------'); 23 | // @ts-ignore 24 | lm.fn_plus('fn_plus'); 25 | } 26 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var decorators; 9 | (function (decorators) { 10 | let Greeter = class Greeter { 11 | constructor(message) { 12 | this.greeting = message; 13 | } 14 | greet() { 15 | return "Hello, " + this.greeting; 16 | } 17 | }; 18 | Greeter = __decorate([ 19 | sealed 20 | ], Greeter); 21 | function sealed(constructor) { 22 | console.log('非扩展类'); 23 | // @ts-ignore 24 | constructor.readme = '静态属性'; 25 | constructor.prototype.readme = () => '实例属性'; 26 | Object.seal(constructor); 27 | Object.seal(constructor.prototype); 28 | // 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。 29 | // 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。 30 | // 注意 如果你要返回一个新的构造函数,你必须注意处理好原来的原型链。 在运行时的装饰器调用逻辑中 不会为你做这些。 31 | // 使用匿名类 + 继承可实现原型链维护和类型「回执」。 32 | return class extends Greeter { 33 | constructor(message, version = 'InnGreeter 1.0') { 34 | super(message); 35 | this.version = version; 36 | // return class InnGreeter extends Greeter{ 37 | this.name = 'extends Greeter'; 38 | } 39 | }; 40 | } 41 | const greeter = new Greeter('greeter'); 42 | // @ts-ignore 43 | console.log(Greeter.readme, greeter.readme()); 44 | console.log(greeter, greeter instanceof Greeter, Greeter.prototype.constructor, Greeter.prototype.constructor === Greeter); 45 | })(decorators || (decorators = {})); 46 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.3.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace decorators { 3 | @sealed 4 | class Greeter { 5 | greeting: string; 6 | constructor(message: string) { 7 | this.greeting = message; 8 | } 9 | greet() { 10 | return "Hello, " + this.greeting; 11 | } 12 | } 13 | 14 | function sealed(constructor: T){ 15 | console.log('非扩展类'); 16 | // @ts-ignore 17 | constructor.readme = '静态属性'; 18 | constructor.prototype.readme = () => '实例属性'; 19 | Object.seal(constructor); 20 | Object.seal(constructor.prototype); 21 | 22 | // 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。 23 | // 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。 24 | // 注意 如果你要返回一个新的构造函数,你必须注意处理好原来的原型链。 在运行时的装饰器调用逻辑中 不会为你做这些。 25 | // 使用匿名类 + 继承可实现原型链维护和类型「回执」。 26 | return class extends Greeter{ 27 | // return class InnGreeter extends Greeter{ 28 | readonly name: string = 'extends Greeter'; 29 | constructor(message: string, public version: string = 'InnGreeter 1.0') { 30 | super(message); 31 | } 32 | }; 33 | } 34 | 35 | const greeter = new Greeter('greeter'); 36 | // @ts-ignore 37 | console.log(Greeter.readme, greeter.readme()); 38 | console.log(greeter, greeter instanceof Greeter, Greeter.prototype.constructor 39 | , Greeter.prototype.constructor === Greeter); 40 | } 41 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.4.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | Object.defineProperty(exports, "__esModule", { value: true }); 9 | require("reflect-metadata"); 10 | var decorators; 11 | (function (decorators) { 12 | // @ts-ignore 13 | var formatMetadataKey = Symbol("format"); 14 | var format; 15 | (function (format) { 16 | format[format["toUpperCase"] = 0] = "toUpperCase"; 17 | format[format["toLowerCase"] = 1] = "toLowerCase"; 18 | format[format["toLocaleUpperCase"] = 2] = "toLocaleUpperCase"; 19 | format[format["toLocaleLowerCase"] = 3] = "toLocaleLowerCase"; 20 | })(format || (format = {})); 21 | /** 22 | * 当 @format("Hello, %s")被调用时,它添加一条这个属性的元数据,通过reflect-metadata库里的Reflect.metadata函数。 23 | * 当 getFormat被调用时,它读取格式的元数据。 24 | */ 25 | var Greeter = /** @class */ (function () { 26 | function Greeter(message) { 27 | this.greeting = message; 28 | } 29 | Greeter.prototype.greet = function () { 30 | var formatType = getFormat(this, "greeting"); 31 | return format[formatType] + ": " + this.greeting[format[formatType] || 0](); 32 | }; 33 | __decorate([ 34 | Reflect.metadata(formatMetadataKey, format.toLocaleUpperCase) 35 | ], Greeter.prototype, "greeting", void 0); 36 | return Greeter; 37 | }()); 38 | function getFormat(target, propertyKey) { 39 | console.log(target, propertyKey); 40 | return Reflect.getMetadata(formatMetadataKey, target, propertyKey); 41 | } 42 | var greeter = new Greeter('Greeter'); 43 | console.log(greeter.greet()); 44 | })(decorators || (decorators = {})); 45 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.4.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import "reflect-metadata"; 3 | 4 | namespace decorators { 5 | // @ts-ignore 6 | const formatMetadataKey = Symbol("format"); 7 | 8 | enum format { 9 | toUpperCase, 10 | toLowerCase, 11 | toLocaleUpperCase, 12 | toLocaleLowerCase 13 | } 14 | 15 | /** 16 | * 当 @format("Hello, %s")被调用时,它添加一条这个属性的元数据,通过reflect-metadata库里的Reflect.metadata函数。 17 | * 当 getFormat被调用时,它读取格式的元数据。 18 | */ 19 | class Greeter { 20 | @Reflect.metadata(formatMetadataKey, format.toLocaleUpperCase) 21 | greeting: string; 22 | 23 | constructor(message: string) { 24 | this.greeting = message; 25 | } 26 | 27 | greet() { 28 | let formatType = getFormat(this, "greeting"); 29 | return `${format[formatType]}: ${this.greeting[format[formatType] || 0]()}`; 30 | } 31 | } 32 | 33 | function getFormat(target: any, propertyKey: string) { 34 | console.log(target, propertyKey); 35 | return Reflect.getMetadata(formatMetadataKey, target, propertyKey); 36 | } 37 | 38 | const greeter = new Greeter('Greeter'); 39 | console.log(greeter.greet()); 40 | } 41 | -------------------------------------------------------------------------------- /TS/code/decorators/decorators.5.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"decorators.5.js","sourceRoot":"","sources":["decorators.5.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;AACb,4BAA0B;AAE1B,IAAU,UAAU,CAgEnB;AAhED,WAAU,UAAU;IAOhB,aAAa;IACb,IAAM,mBAAmB,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAE/C;QAGI,iBAAY,OAAe;YACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,CAAC;QAED,oBAAE,GAAF,cAAM,CAAC;QAGP,uBAAK,GAAL,UAAM,EAAE,EAAE,EAAE,EAAE,EAAE,EAAY,IAAY,EAAE,EAAE;YACxC,oCAAoC;YACpC,OAAO,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAClD,CAAC;QAHD;YADC,QAAQ;YACU,WAAA,QAAQ,CAAA;;;;4CAG1B;QACL,cAAC;KAAA,AAdD,IAcC;IAED,aAAa;IACb,SAAS,QAAQ,CAAC,MAAc,EAAE,WAA4B,EAAE,cAAsB;QAClF,8EAA8E;QAC9E,kCAAkC;QAClC,IAAI,0BAA0B,GAAsB,OAAO,CAAC,cAAc,CAAC,mBAAmB,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;QAC3H,0BAA0B,CAAC,IAAI,CAAC;YAC5B,KAAK,EAAE,cAAc;YACrB,MAAM,EAAE,WAAW;YACnB,YAAY,EAAE,MAAM,CAAC,WAAW;SACnC,CAAC,CAAC;QACH,QAAQ,CAAC;QACT,OAAO,CAAC,cAAc,CAAC,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IACjG,CAAC;IAED,kBAAkB;IAClB,SAAS,QAAQ,CAAC,MAAW,EAAE,YAAoB,EAAE,UAA6C;QAC9F,IAAI,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;QAC9B,UAAU,CAAC,KAAK,GAAG;YACf,IAAI,kBAAkB,GAAsB,OAAO,CAAC,cAAc,CAAC,mBAAmB,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;YAC9G,IAAI,kBAAkB,EAAE;gBACpB,KAA4C,UAAkB,EAAlB,yCAAkB,EAAlB,gCAAkB,EAAlB,IAAkB,EAAE;oBAAvD,IAAA,6BAA+B,EAA7B,gBAAK,EAAE,oBAAM,EAAE,8BAAY;oBAClC,IAAI,KAAK,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,SAAS,EAAE;wBAC7D,wCAAwC;wBACxC,aAAa;wBACb,MAAM,CAAI,YAAY,CAAC,IAAI,SAAI,MAAM,CAAC,QAAM,CAAC,UAAK,YAAY,CAAC,IAAI,mBAAc,MAAM,CAAC,QAAM,CAAC,mBAAQ,KAAK,GAAG,CAAC,qFAAgB,CAAC,CAAC;wBAClI,iDAAiD;qBACpD;iBACJ;aACJ;YAED,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC,CAAA;IACL,CAAC;IAED,IAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAEvC,aAAa;IACb,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;AACjC,CAAC,EAhES,UAAU,KAAV,UAAU,QAgEnB"} -------------------------------------------------------------------------------- /TS/code/decorators/decorators.5.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import "reflect-metadata"; 3 | 4 | namespace decorators { 5 | type paramDecorators = { 6 | index: number, 7 | method: string | symbol, 8 | constructors: Function, 9 | }; 10 | 11 | // @ts-ignore 12 | const requiredMetadataKey = Symbol("required"); 13 | 14 | class Greeter { 15 | greeting: string; 16 | 17 | constructor(message: string) { 18 | this.greeting = message; 19 | } 20 | 21 | fn() {} 22 | 23 | @validate 24 | greet(p1, p2, p3, @required name: string, p5) { 25 | // loc 仅仅用于占位, 用来测试 required 的第三个参数。 26 | return "Hello " + name + ", " + this.greeting; 27 | } 28 | } 29 | 30 | // 属性装饰器优先级更高 31 | function required(target: Object, propertyKey: string | symbol, parameterIndex: number) { 32 | // console.log(`method: ${propertyKey},第 ${parameterIndex + 1} 个参数。`); 33 | // 可能有多个 属性装饰器, 所以需要去 push 到已有队列中。 34 | let existingRequiredParameters: paramDecorators[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || []; 35 | existingRequiredParameters.push({ 36 | index: parameterIndex, 37 | method: propertyKey, 38 | constructors: target.constructor, 39 | }); 40 | debugger; 41 | Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey); 42 | } 43 | 44 | // 方法装饰器: greet 增强 45 | function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor) { 46 | let method = descriptor.value; 47 | descriptor.value = function () { 48 | let requiredParameters: paramDecorators[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName); 49 | if (requiredParameters) { 50 | for (let { index, method, constructors } of requiredParameters) { 51 | if (index >= arguments.length || arguments[index] === undefined) { 52 | // 只是为了说明问题, 实际上 method 并非直接挂在 class 上的。 53 | // @ts-ignore 54 | throw (`${constructors.name}.${String(method)}[ ${constructors.name}.prototype.${String(method)} ] 第 ${index + 1} 个参数是必传参数,请提供。`); 55 | // throw new Error("Missing required argument."); 56 | } 57 | } 58 | } 59 | 60 | return method.apply(this, arguments); 61 | } 62 | } 63 | 64 | const greeter = new Greeter('greeter'); 65 | 66 | // @ts-ignore 67 | console.log(greeter.greet()); 68 | } 69 | -------------------------------------------------------------------------------- /TS/code/decorators/readme.md: -------------------------------------------------------------------------------- 1 | 使用如下命令编译: 2 | 3 | node > 9 4 | 5 | tsc --target ES6 --experimentalDecorators xx.ts && node xx.js 6 | 7 | 如果报错可以使用: ES5, 使用了 reflect-metadata .需要添加 --emitDecoratorMetadata 参数。 8 | 9 | tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata xx.ts && node xx.js 10 | 11 | 调试 12 | 13 | tsc --sourceMap --target ES5 --experimentalDecorators --emitDecoratorMetadata decorators.5.ts && ndb decorators.5.js 14 | -------------------------------------------------------------------------------- /TS/code/fileTypeChecking/ftc.1.js: -------------------------------------------------------------------------------- 1 | // @ts-check 开启类型检查和错误提示 2 | 3 | 4 | /** @type {number} */ 5 | let ftc; 6 | 7 | ftc = 0; // OK 8 | // @ts-ignore: 忽略本行错误 9 | ftc = false; // Error: boolean is not assignable to number 10 | -------------------------------------------------------------------------------- /TS/code/fileTypeChecking/ftc.1.ts.js: -------------------------------------------------------------------------------- 1 | // @ts-check 开启类型检查和错误提示 2 | /** @type {number} */ 3 | var ftc; 4 | ftc = 0; // OK 5 | // @ts-ignore 6 | ftc = false; // Error: boolean is not assignable to number 7 | -------------------------------------------------------------------------------- /TS/code/generics/generics.1.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 使用泛型定义函数后,函数体的实现却显得很不自由。简单的操作都有很多限制,考虑类型和转换等问题。 3 | * 很多类型不能断言到具体类型,不得不将其 any 化。 4 | * 其实与其转成 any 还不如使用 any 或者 直接不写类型。徒增复杂度。 5 | * 6 | * 如下提供了两种设计方案解决上述问题 7 | */ 8 | namespace generics1 { 9 | // 泛型和实现分离 10 | interface Animal { 11 | // 联合类型 U | V 12 | eat(food: T): U | V; 13 | } 14 | 15 | class Dog implements Animal { 16 | // U | V => string | null 17 | eat(food: Food): string | null{ 18 | return food.name; 19 | } 20 | 21 | static eat(food: Food): string { 22 | return food.name; 23 | } 24 | } 25 | 26 | class Food { 27 | constructor(public name: string) {} 28 | } 29 | 30 | const eatWhat = new Dog().eat(new Food('骨头')); 31 | 32 | console.log(eatWhat); 33 | } 34 | 35 | namespace generics2 { 36 | // 使用接口将函数泛型转移到抽象描述上,使用匿名函数表达式实现抽象描述。 也能做解决上述问题。 37 | interface GenericIdentityFn { 38 | (arg: T): T; 39 | } 40 | 41 | let myIdentity: GenericIdentityFn = function (n: number): number { 42 | return n ** 2; 43 | } 44 | 45 | console.log(myIdentity(5)); 46 | } 47 | 48 | namespace generics3 { 49 | /** 50 | * 官方提供的方案, 我认为很别扭。可能只是个说明。 51 | */ 52 | class GenericNumber { 53 | zeroValue: T; 54 | // 属性化化方法。我认为不是一种好的实现 55 | add: (x: T, y: T) => T; 56 | } 57 | 58 | let myGenericNumber = new GenericNumber(); 59 | myGenericNumber.zeroValue = 0; 60 | myGenericNumber.add = function (x, y) { return x + y; }; 61 | } 62 | 63 | namespace generics4 { 64 | // 定义泛型规范用来解决上述问题。 65 | interface Lengthwise { 66 | length: number; 67 | } 68 | 69 | function loggingIdentity(arg: T): T { 70 | console.log(arg.length); // Now we know it has a .length property, so no more error 71 | return arg; 72 | } 73 | 74 | // error: 如果如下方式能成功, 则此方案是个好选择, 局限性还是比较大 75 | // function loggingIdentity_1(arg: T): T { 76 | // return arg++; 77 | // } 78 | } 79 | -------------------------------------------------------------------------------- /TS/code/generics/generics.2.ts: -------------------------------------------------------------------------------- 1 | class BeeKeeper { 2 | hasMask: boolean = true; 3 | } 4 | 5 | class ZooKeeper { 6 | nametag: string = 'ZooKeeper'; 7 | } 8 | 9 | class Animal { 10 | numLegs: number; 11 | } 12 | 13 | class Bee extends Animal { 14 | keeper: BeeKeeper = new BeeKeeper(); 15 | } 16 | 17 | class Lion extends Animal { 18 | keeper: ZooKeeper = new ZooKeeper(); 19 | } 20 | 21 | // 泛型约束构造, 其中 c: new () => A 是构造描述, 即类类型。 22 | function createInstance(c: new () => A): A { 23 | return new c(); 24 | } 25 | 26 | const nametag = createInstance(Lion).keeper.nametag; // ZooKeeper! 27 | const hasMask = createInstance(Bee).keeper.hasMask; // true! 28 | 29 | console.log(nametag, hasMask); 30 | -------------------------------------------------------------------------------- /TS/code/interface/interface.1.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 基础接口继承模型 3 | */ 4 | 5 | // 抽象接口 6 | interface Animal { 7 | age: number; 8 | height: number; 9 | widget: number; 10 | 11 | say(): string; 12 | } 13 | 14 | interface Personal { 15 | readonly name: string; 16 | 17 | talk(): Personal; 18 | } 19 | 20 | 21 | // 数据描述接口 22 | interface ChineseInterfaceData { 23 | sel: number; 24 | age: number; 25 | name: string; 26 | height?: number; 27 | widget?: number; 28 | } 29 | 30 | class Chinese implements Animal, Personal { 31 | age: number; 32 | name: string; 33 | height: number; 34 | public widget: number; 35 | protected readonly sel: number; 36 | 37 | constructor({ 38 | sel, 39 | name, 40 | age = 0, 41 | widget = 0, 42 | height = 0, 43 | }: ChineseInterfaceData = {}) { 44 | this.name = name; 45 | this.age = age; 46 | this.widget = widget; 47 | this.height = height; 48 | 49 | this.sel = sel; 50 | }; 51 | 52 | talk(): Chinese { 53 | return this; 54 | }; 55 | 56 | say(): string { 57 | return `${this.name}, ${this.age}`; 58 | }; 59 | } 60 | 61 | 62 | const lm: Chinese = new Chinese({ name: 'lm', age: 10, sel: 10000 }); 63 | 64 | console.log(lm); 65 | -------------------------------------------------------------------------------- /TS/code/interface/interface.2.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 接口继承, 抽象类, 3 | */ 4 | 5 | // 这个接口用于描述构造器 6 | interface ClockConstructor { 7 | new(hour: number, minute: number): ClockInterface; 8 | } 9 | interface ClockInterface { 10 | h: number; 11 | m: number; 12 | tick(); 13 | help(); 14 | } 15 | 16 | // 抽象类。 17 | abstract class ClockInterfaceAbs implements ClockInterface{ 18 | h: number; 19 | m: number; 20 | 21 | constructor(h: number, m: number) { 22 | this.h = h; 23 | this.m = m 24 | } 25 | 26 | abstract help(); 27 | 28 | tick(): string { 29 | return `(h: ${this.h}, m: ${this.m})`; 30 | } 31 | } 32 | 33 | // 模拟时钟 34 | class DigitalClock extends ClockInterfaceAbs { 35 | // 如果没有扩展属性,可以省略,交给抽象了统一处理, 如果有 调用 super。 36 | // constructor(h: number, m: number) { 37 | // super(h, m); 38 | // } 39 | help() {} 40 | } 41 | 42 | // 数码时钟 43 | class AnalogClock extends ClockInterfaceAbs { 44 | help() { } 45 | } 46 | 47 | /** 48 | * 49 | * @param ctor 构造函数: 由 ClockConstructor 描述并约束 50 | * @param hour 51 | * @param minute 52 | */ 53 | function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { 54 | return new ctor(hour, minute); 55 | } 56 | 57 | let digital = createClock(DigitalClock, 12, 17); 58 | let analog = createClock(AnalogClock, 7, 32); 59 | 60 | console.log(digital, analog); 61 | 62 | console.log(digital.tick()); 63 | -------------------------------------------------------------------------------- /TS/code/interface/interface.3.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 接口多实现, 接口继承接口 3 | * 4 | * 和类一样,接口也可以相互继承。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。 5 | * 6 | * 一个接口可以继承多个接口,创建出多个接口的合成接口。 7 | */ 8 | 9 | namespace i3 { 10 | interface A1 { 11 | a1: number; 12 | } 13 | 14 | interface A2 { 15 | a2: number; 16 | } 17 | 18 | interface B extends A1, A2 { 19 | b: number; 20 | } 21 | 22 | interface C { 23 | c: number; 24 | } 25 | 26 | class D { } 27 | 28 | class E extends D implements B, C { 29 | a1: number; 30 | a2: number; 31 | b: number; 32 | c: number; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TS/code/module/demo/LettersOnlyValidator.ts: -------------------------------------------------------------------------------- 1 | import {StringValidator} from './StringValidator'; 2 | 3 | export class LettersOnlyValidator implements StringValidator { 4 | isAcceptable(s: string) { 5 | const lettersRegexp = /^[A-Za-z]+$/; 6 | return lettersRegexp.test(s); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /TS/code/module/demo/StringValidator.ts: -------------------------------------------------------------------------------- 1 | export interface StringValidator { 2 | isAcceptable(s: string): boolean; 3 | } 4 | -------------------------------------------------------------------------------- /TS/code/module/demo/ZipCodeValidator.ts: -------------------------------------------------------------------------------- 1 | import { StringValidator } from './StringValidator'; 2 | 3 | export class ZipCodeValidator implements StringValidator { 4 | isAcceptable(s: string) { 5 | const numberRegexp = /^[0-9]+$/; 6 | return s.length === 5 && numberRegexp.test(s); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /TS/code/module/demo/build/LettersOnlyValidator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var LettersOnlyValidator = /** @class */ (function () { 4 | function LettersOnlyValidator() { 5 | } 6 | LettersOnlyValidator.prototype.isAcceptable = function (s) { 7 | var lettersRegexp = /^[A-Za-z]+$/; 8 | return lettersRegexp.test(s); 9 | }; 10 | return LettersOnlyValidator; 11 | }()); 12 | exports.LettersOnlyValidator = LettersOnlyValidator; 13 | -------------------------------------------------------------------------------- /TS/code/module/demo/build/StringValidator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | -------------------------------------------------------------------------------- /TS/code/module/demo/build/ZipCodeValidator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var ZipCodeValidator = /** @class */ (function () { 4 | function ZipCodeValidator() { 5 | } 6 | ZipCodeValidator.prototype.isAcceptable = function (s) { 7 | var numberRegexp = /^[0-9]+$/; 8 | return s.length === 5 && numberRegexp.test(s); 9 | }; 10 | return ZipCodeValidator; 11 | }()); 12 | exports.ZipCodeValidator = ZipCodeValidator; 13 | -------------------------------------------------------------------------------- /TS/code/module/demo/build/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var ZipCodeValidator_1 = require("./ZipCodeValidator"); 4 | var LettersOnlyValidator_1 = require("./LettersOnlyValidator"); 5 | // Some samples to try 6 | var strings = ["Hello", "98052", "101"]; 7 | // Validators to use 8 | var validators = {}; 9 | validators["ZIP code"] = new ZipCodeValidator_1.ZipCodeValidator(); 10 | validators["Letters only"] = new LettersOnlyValidator_1.LettersOnlyValidator(); 11 | // Show whether each string passed each validator 12 | strings.forEach(function (s) { 13 | for (var name_1 in validators) { 14 | console.log("\"" + s + "\" - " + (validators[name_1].isAcceptable(s) ? "matches" : "does not match") + " " + name_1); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /TS/code/module/demo/main.ts: -------------------------------------------------------------------------------- 1 | import { StringValidator } from './StringValidator' 2 | import { ZipCodeValidator } from './ZipCodeValidator' 3 | import { LettersOnlyValidator } from './LettersOnlyValidator' 4 | 5 | // Some samples to try 6 | let strings = ["Hello", "98052", "101"]; 7 | 8 | // Validators to use 9 | let validators: { [s: string]: StringValidator; } = {}; 10 | validators["ZIP code"] = new ZipCodeValidator(); 11 | validators["Letters only"] = new LettersOnlyValidator(); 12 | 13 | // Show whether each string passed each validator 14 | strings.forEach(s => { 15 | for (let name in validators) { 16 | console.log(`"${s}" - ${validators[name].isAcceptable(s) ? "matches" : "does not match"} ${name}`); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /TS/code/module/module_export.1.ts: -------------------------------------------------------------------------------- 1 | class ZipCodeValidator{ 2 | 3 | } 4 | 5 | export {ZipCodeValidator}; 6 | -------------------------------------------------------------------------------- /TS/code/module/module_import.1.ts: -------------------------------------------------------------------------------- 1 | 2 | import { ZipCodeValidator as Zip } from "./module_export.1"; 3 | 4 | if (true) { 5 | let validator = new Zip(); 6 | console.log(validator); 7 | } 8 | 9 | import ZipCodeValidator = require("./module_export.1"); 10 | -------------------------------------------------------------------------------- /TS/code/namespace/namespace.1.js: -------------------------------------------------------------------------------- 1 | var n1; 2 | (function (n1) { 3 | function fn() { 4 | return 'namespace.2.ts >> namespace: n1'; 5 | } 6 | n1.fn = fn; 7 | ; 8 | })(n1 || (n1 = {})); 9 | var n2; 10 | (function (n2) { 11 | var Vue = /** @class */ (function () { 12 | function Vue() { 13 | } 14 | return Vue; 15 | }()); 16 | n2.Vue = Vue; 17 | })(n2 || (n2 = {})); 18 | /// 19 | /** 20 | * 这么写需要将多个文件编译到一个文件中: tsc --outFile namespace.1.js namespace.1.ts 21 | * 然后 node namespace.1.js 执行。 否则两个文件没法建立联系。 22 | */ 23 | var n1; 24 | (function (n1) { 25 | var x = 10; 26 | console.log(n1.fn()); 27 | ; 28 | })(n1 || (n1 = {})); 29 | var n2; 30 | (function (n2) { 31 | new n2.Vue(); 32 | var Person = /** @class */ (function () { 33 | function Person(name, age) { 34 | this.name = name; 35 | this.age = age; 36 | } 37 | return Person; 38 | }()); 39 | n2.Person = Person; 40 | })(n2 || (n2 = {})); 41 | // 同文件 多个 namespace 不通用 42 | (function (n2) { 43 | // error: Cannot find name 'Person'. 44 | new n2.Person(); 45 | })(n2 || (n2 = {})); 46 | -------------------------------------------------------------------------------- /TS/code/namespace/namespace.1.ts: -------------------------------------------------------------------------------- 1 | 2 | /// 3 | 4 | /** 5 | * 这么写需要将多个文件编译到一个文件中: tsc --outFile namespace.1.js namespace.1.ts 6 | * 然后 node namespace.1.js 执行。 否则两个文件没法建立联系。 7 | */ 8 | namespace n1{ 9 | let x = 10; 10 | console.log(fn());; 11 | } 12 | 13 | namespace n2 { 14 | new Vue(); 15 | 16 | export class Person { 17 | constructor(public name: string, public age: number) {} 18 | } 19 | } 20 | 21 | // 同文件 多个 namespace 也需要 export 22 | namespace n2 { 23 | new Person('liming', 13); 24 | } 25 | -------------------------------------------------------------------------------- /TS/code/namespace/namespace.2.ts: -------------------------------------------------------------------------------- 1 | 2 | namespace n1{ 3 | export function fn() { 4 | return 'namespace.2.ts >> namespace: n1' 5 | }; 6 | } 7 | 8 | namespace n2 { 9 | export class Vue{} 10 | } 11 | -------------------------------------------------------------------------------- /TS/code/namespace/namespace.3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/namespace/namespace.3.ts -------------------------------------------------------------------------------- /TS/code/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "reflect-metadata": { 8 | "version": "0.1.12", 9 | "resolved": "http://registry.npm.taobao.org/reflect-metadata/download/reflect-metadata-0.1.12.tgz", 10 | "integrity": "sha1-MRvwxrY814LyKKgavhRqK/qcVvI=" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TS/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "reflect-metadata": "^0.1.12" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Animal/Animal.abs.js: -------------------------------------------------------------------------------- 1 | import Tools from '../Tool'; 2 | const { Log } = Tools; 3 | class AbsAnimal { 4 | constructor(_name) { 5 | this._name = _name; 6 | } 7 | sleep() { 8 | Log(`${this.name}:eat too much, need to sleep.`); 9 | } 10 | ; 11 | get name() { 12 | return this._name; 13 | } 14 | } 15 | export default AbsAnimal; 16 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Animal/Animal.interface.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/polymorphism/build/Animal/Animal.interface.js -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Animal/Animal_abs.js: -------------------------------------------------------------------------------- 1 | import Tools from '../Tool'; 2 | const { Log } = Tools; 3 | class AbsAnimal { 4 | constructor(_name, _maxEnergy = 100, _curEnergy = 0) { 5 | this._name = _name; 6 | this._maxEnergy = _maxEnergy; 7 | this._curEnergy = _curEnergy; 8 | } 9 | sleep() { 10 | const costEnergy = this._maxEnergy / 2; 11 | this._curEnergy -= costEnergy; 12 | Log(`${this.name}:eat too much, need to sleep.`); 13 | // 抽象类批量切换实现 14 | // Log(`${this.name}:eat too much, need to sleep. will cost ${costEnergy} energy.`); 15 | } 16 | // play(): void { 17 | // // this._curEnergy -= 10; 18 | // Log(`${this.name}:play.`); 19 | // } 20 | /** 21 | * get set 同访问修饰符有点蛋疼, 实际上想要做这样的场景就比较麻烦: 22 | * 所有人都可以访问名字, 但只有实例自己能修改名字。 23 | */ 24 | get name() { 25 | return this._name; 26 | } 27 | // set name(newName: string) { 28 | // this._name = newName; 29 | // } 30 | get maxEnergy() { 31 | return this._maxEnergy; 32 | } 33 | // set maxEnergy(newMaxEnergy: number) { 34 | // this._maxEnergy = newMaxEnergy; 35 | // } 36 | get curEnergy() { 37 | return this._curEnergy; 38 | } 39 | set curEnergy(newCurEnergy) { 40 | this._curEnergy = newCurEnergy; 41 | } 42 | /** 43 | * 实际上可以讲 commonEat 和 eat 合成一个, 在子类里同样的调用 super.eat() 44 | * 但是 eat 在接口中声明了, 所以不能降低访问权限到 protected。 45 | * 46 | * 如果是比较通用的实现,可以提到抽象类中,然后使用 protected 限制使用范围为子类, 也是比较好的方案。 47 | * @param food 48 | */ 49 | commonEat(food) { 50 | const supEnergy = food.supportEnergy(); 51 | this.curEnergy += supEnergy; 52 | return this.curEnergy; 53 | } 54 | ; 55 | } 56 | export default AbsAnimal; 57 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Animal/Animal_interface.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/polymorphism/build/Animal/Animal_interface.js -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Animal/Cat.js: -------------------------------------------------------------------------------- 1 | import AbsAnimal from './Animal_abs'; 2 | import Tools from '../Tool'; 3 | class Cat extends AbsAnimal { 4 | eat(food) { 5 | const curEnergy = super.commonEat(food); 6 | Tools.Log(`${this.name} like eat ${food.name}. now have ${curEnergy} energy.`); 7 | return true; 8 | } 9 | // override. 10 | sleep() { 11 | Tools.Log(`${this.name}:白天睡觉,晚上留着肚子吃老鼠!`); 12 | } 13 | } 14 | export default Cat; 15 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Animal/Dog.js: -------------------------------------------------------------------------------- 1 | import AbsAnimal from './Animal_abs'; 2 | import Tools from '../Tool'; 3 | const { Log } = Tools; 4 | /** 5 | * 这里的设计在接口和实现类之间加了一层抽象类,实现类就不要直接和抽象类交互 6 | */ 7 | class Dog extends AbsAnimal { 8 | eat(food) { 9 | return new Promise((resolve /*, reject*/) => { 10 | const supEnergy = food.supportEnergy(); 11 | this.curEnergy += supEnergy; 12 | const { maxEnergy, curEnergy } = this; 13 | Log(`${this.name} like eat ${food.name}/${supEnergy}, and now my Energy from ${curEnergy - supEnergy} to ${curEnergy} (maxEnergy=${maxEnergy})`); 14 | curEnergy >= maxEnergy ? resolve(true) : resolve(false); 15 | }); 16 | } 17 | } 18 | export default Dog; 19 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Breeder.js: -------------------------------------------------------------------------------- 1 | export default class Breeder { 2 | async feed(animal, food) { 3 | let isEnough; 4 | while (!(isEnough = await animal.eat(food))) 5 | ; 6 | await animal.sleep(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/Bone.js: -------------------------------------------------------------------------------- 1 | import AbsFood from './Food_abs'; 2 | /** 3 | * 这里的设计在接口和实现类之间加了一层抽象类,实现类就不要直接和抽象类交互 4 | */ 5 | class Bone extends AbsFood { 6 | } 7 | export default Bone; 8 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/DogFood.js: -------------------------------------------------------------------------------- 1 | import AbsFood from './Food_abs'; 2 | class DogFood extends AbsFood { 3 | constructor() { 4 | super(...arguments); 5 | this.addition = 2; 6 | } 7 | supportEnergy() { 8 | return this.energy * this.addition; 9 | } 10 | } 11 | export default DogFood; 12 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/DogFood_interface.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/polymorphism/build/Food/DogFood_interface.js -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/Fish.js: -------------------------------------------------------------------------------- 1 | import AbsFood from './Food_abs'; 2 | class Fish extends AbsFood { 3 | constructor() { 4 | super(...arguments); 5 | this.addition = 0.8; 6 | } 7 | supportEnergy() { 8 | return this._energy * this.addition; 9 | } 10 | } 11 | export default Fish; 12 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/Food.abs.js: -------------------------------------------------------------------------------- 1 | class AbsFood { 2 | constructor(_name) { 3 | this._name = _name; 4 | } 5 | get name() { 6 | return this._name; 7 | } 8 | } 9 | export default AbsFood; 10 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/Food.interface.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/polymorphism/build/Food/Food.interface.js -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/Food_abs.js: -------------------------------------------------------------------------------- 1 | class AbsFood { 2 | constructor(_name, _energy) { 3 | this._name = _name; 4 | this._energy = _energy; 5 | } 6 | supportEnergy() { 7 | return this.energy; 8 | } 9 | get name() { 10 | return this._name; 11 | } 12 | get energy() { 13 | return this._energy; 14 | } 15 | } 16 | export default AbsFood; 17 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Food/Food_interface.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/polymorphism/build/Food/Food_interface.js -------------------------------------------------------------------------------- /TS/code/polymorphism/build/Tool.js: -------------------------------------------------------------------------------- 1 | export default class Tools { 2 | // 重载函数体: 参数是可选参数 3 | static Log(data) { 4 | if (data) { 5 | const dataStr = JSON.stringify(Object(data), null, 4); 6 | console.log(); 7 | console.log(dataStr); 8 | return dataStr; 9 | } 10 | else { 11 | console.log(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TS/code/polymorphism/build/main.js: -------------------------------------------------------------------------------- 1 | import Breeder from './Breeder'; 2 | import Tool from './Tool'; 3 | import Fish from './Food/Fish'; 4 | import Bone from './Food/Bone'; 5 | import DogFood from './Food/DogFood'; 6 | import Dog from './Animal/Dog'; 7 | import Cat from './Animal/Cat'; 8 | class BreederManager { 9 | constructor() { 10 | this._breeder = new Breeder(); 11 | } 12 | async main() { 13 | await this.testOne(); 14 | await this.testTwo(); 15 | await this.testThree(); 16 | } 17 | async testThree() { 18 | Tool.Log(); 19 | Tool.Log('----------------testThree---------------------'); 20 | const tom = new Cat('Tom'); 21 | const fish = new Fish('鱼', 25); 22 | await this._breeder.feed(tom, fish); 23 | } 24 | async testTwo() { 25 | Tool.Log(); 26 | Tool.Log('----------------testTwo---------------------'); 27 | const yelloDog = new Dog('黄狗'); 28 | const dogFood = new DogFood('狗粮', 25); 29 | await this._breeder.feed(yelloDog, dogFood); 30 | Tool.Log('..........dev..........'); 31 | const bigBone = new Bone('小骨头', 50); 32 | await this._breeder.feed(yelloDog, bigBone); 33 | } 34 | async testOne() { 35 | Tool.Log(); 36 | Tool.Log('----------------testOne---------------------'); 37 | const xiaohuang = new Dog('小黄'); 38 | const smallBone = new Bone('小骨头', 25); 39 | await this._breeder.feed(xiaohuang, smallBone); 40 | Tool.Log('..........dev..........'); 41 | const dahuang = new Dog('大黄'); 42 | const bigBone = new Bone('大骨头', 50); 43 | await this._breeder.feed(dahuang, bigBone); 44 | Tool.Log('..........dev..........'); 45 | await this._breeder.feed(xiaohuang, bigBone); 46 | Tool.Log('..........dev..........'); 47 | await this._breeder.feed(dahuang, smallBone); 48 | } 49 | get breeder() { 50 | return this._breeder; 51 | } 52 | } 53 | new BreederManager().main(); 54 | -------------------------------------------------------------------------------- /TS/code/polymorphism/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "polymorphism", 3 | "version": "1.0.0", 4 | "description": "tsc --outdir ./build -w -t es2017 main.ts", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc --outdir ./build -w -t es2017 ./src/main.ts", 8 | "start": "node --experimental-modules --loader ~/.node.custom-loader.mjs build/main.js", 9 | 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "author": "", 13 | "license": "ISC" 14 | } 15 | -------------------------------------------------------------------------------- /TS/code/polymorphism/readme.md: -------------------------------------------------------------------------------- 1 | yarn build 2 | 3 | yarn start 4 | 5 | or use deno. 6 | need import a or a.js change to a.ts 7 | 8 | # 注意 9 | 1. 文件名不要有「.」号, a.abs.js 改为 a_abs.js 10 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Animal/Animal_abs.ts: -------------------------------------------------------------------------------- 1 | import IAnimal from './Animal_interface' 2 | import Food from '../Food/Food_interface' 3 | import Tools from '../Tool' 4 | 5 | const { Log } = Tools; 6 | 7 | abstract class AbsAnimal implements IAnimal { 8 | constructor(protected _name: string, 9 | protected _maxEnergy: number = 100, 10 | protected _curEnergy: number = 0) {} 11 | 12 | sleep(): void { 13 | const costEnergy = this._maxEnergy / 2; 14 | this._curEnergy -= costEnergy; 15 | Log(`${this.name}:eat too much, need to sleep.`); 16 | // 抽象类批量切换实现 17 | // Log(`${this.name}:eat too much, need to sleep. will cost ${costEnergy} energy.`); 18 | } 19 | 20 | // play(): void { 21 | // // this._curEnergy -= 10; 22 | // Log(`${this.name}:play.`); 23 | // } 24 | 25 | /** 26 | * get set 同访问修饰符有点蛋疼, 实际上想要做这样的场景就比较麻烦: 27 | * 所有人都可以访问名字, 但只有实例自己能修改名字。 28 | */ 29 | get name(): string { 30 | return this._name; 31 | } 32 | // set name(newName: string) { 33 | // this._name = newName; 34 | // } 35 | 36 | get maxEnergy(): number { 37 | return this._maxEnergy; 38 | } 39 | // set maxEnergy(newMaxEnergy: number) { 40 | // this._maxEnergy = newMaxEnergy; 41 | // } 42 | 43 | protected get curEnergy(): number { 44 | return this._curEnergy; 45 | } 46 | protected set curEnergy(newCurEnergy: number) { 47 | this._curEnergy = newCurEnergy; 48 | } 49 | 50 | /** 51 | * 52 | * @param food 53 | * 54 | * 这里到底是依赖接口还是依赖抽象类?理论上应该依赖最抽象的层次,考虑了很多情况, 还是应该依赖接口。 55 | * 原因在于: 我们添加抽象类则是为了解决接口扩充的问题,接口本身还是规范,抽象类并不是, 或者一个 56 | * 完整的继承描述层次不应该有多个规范存在, 如果有接口,那就只能依赖接口 57 | */ 58 | abstract eat(food: Food): any; 59 | /** 60 | * 实际上可以讲 commonEat 和 eat 合成一个, 在子类里同样的调用 super.eat() 61 | * 但是 eat 在接口中声明了, 所以不能降低访问权限到 protected。 62 | * 63 | * 如果是比较通用的实现,可以提到抽象类中,然后使用 protected 限制使用范围为子类, 也是比较好的方案。 64 | * @param food 65 | */ 66 | protected commonEat(food: Food): any { 67 | const supEnergy = food.supportEnergy(); 68 | this.curEnergy += supEnergy; 69 | 70 | return this.curEnergy; 71 | }; 72 | } 73 | 74 | export default AbsAnimal; 75 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Animal/Animal_interface.ts: -------------------------------------------------------------------------------- 1 | import Food from '../Food/Food_interface' 2 | 3 | interface Animal { 4 | // eat(food: Food): Promise; 5 | // 尽量避免在接口中声明属性, 因为接口字段都是 public 的, 但实际情况中,很少有属性会直接设计成 public。 6 | // 属性一般是私有的, 行为是共享的。 7 | // curEnergy: string; 8 | name: string; 9 | // TODO 这里返回 any 显然不是一个好的做法, 偷懒。 稍后用泛型改造。 10 | eat(food: Food): any; 11 | sleep(): void; 12 | // play(): void; 13 | } 14 | 15 | export default Animal; 16 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Animal/Cat.ts: -------------------------------------------------------------------------------- 1 | import AbsAnimal from './Animal_abs' 2 | import Food from '../Food/Food_interface' 3 | 4 | import Tools from '../Tool' 5 | 6 | class Cat extends AbsAnimal { 7 | eat(food: Food): boolean { 8 | const curEnergy = super.commonEat(food); 9 | 10 | Tools.Log(`${this.name} like eat ${food.name}. now have ${curEnergy} energy.`); 11 | return true; 12 | } 13 | 14 | // override. 15 | sleep(): void { 16 | Tools.Log(`${this.name}:白天睡觉,晚上留着肚子吃老鼠!`); 17 | } 18 | } 19 | 20 | export default Cat; 21 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Animal/Dog.ts: -------------------------------------------------------------------------------- 1 | import AbsAnimal from './Animal_abs' 2 | import Food from '../Food/Food_interface' 3 | 4 | import Tools from '../Tool' 5 | 6 | const { Log } = Tools; 7 | /** 8 | * 这里的设计在接口和实现类之间加了一层抽象类,实现类就不要直接和抽象类交互 9 | */ 10 | class Dog extends AbsAnimal { 11 | eat(food: Food): Promise { 12 | return new Promise((resolve/*, reject*/) => { 13 | const supEnergy = food.supportEnergy(); 14 | this.curEnergy += supEnergy; 15 | 16 | const { maxEnergy, curEnergy } = this; 17 | Log(`${this.name} like eat ${food.name}/${supEnergy}, and now my Energy from ${curEnergy - supEnergy} to ${curEnergy} (maxEnergy=${maxEnergy})`); 18 | 19 | curEnergy >= maxEnergy ? resolve(true) : resolve(false); 20 | }) 21 | } 22 | } 23 | 24 | export default Dog; 25 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Breeder.ts: -------------------------------------------------------------------------------- 1 | import Animal from './Animal/Animal_interface'; 2 | import Food from './Food/Food_interface'; 3 | 4 | export default class Breeder { 5 | async feed(animal: Animal, food: Food) { 6 | let isEnough: boolean; 7 | while (!(isEnough = await animal.eat(food))); 8 | 9 | await animal.sleep(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Food/Bone.ts: -------------------------------------------------------------------------------- 1 | import AbsFood from './Food_abs' 2 | 3 | /** 4 | * 这里的设计在接口和实现类之间加了一层抽象类,实现类就不要直接和抽象类交互 5 | */ 6 | class Bone extends AbsFood { 7 | 8 | } 9 | 10 | export default Bone; 11 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Food/DogFood.ts: -------------------------------------------------------------------------------- 1 | import AbsFood from './Food_abs' 2 | 3 | class DogFood extends AbsFood { 4 | private addition: number = 2; 5 | supportEnergy(): number { 6 | return this.energy * this.addition; 7 | } 8 | } 9 | 10 | export default DogFood; 11 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Food/Fish.ts: -------------------------------------------------------------------------------- 1 | import AbsFood from './Food_abs' 2 | 3 | class Fish extends AbsFood { 4 | private addition: number = 0.8; 5 | supportEnergy(): number { 6 | return this._energy * this.addition; 7 | } 8 | } 9 | 10 | export default Fish; 11 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Food/Food_abs.ts: -------------------------------------------------------------------------------- 1 | import IFood from './Food_interface' 2 | 3 | abstract class AbsFood implements IFood { 4 | constructor(protected _name: string, 5 | protected _energy: number) {} 6 | 7 | supportEnergy(): number { 8 | return this.energy; 9 | } 10 | 11 | get name(): string { 12 | return this._name; 13 | } 14 | 15 | get energy(): number { 16 | return this._energy; 17 | } 18 | } 19 | 20 | export default AbsFood; 21 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Food/Food_interface.ts: -------------------------------------------------------------------------------- 1 | interface Food { 2 | name: string; 3 | supportEnergy(): number; 4 | } 5 | 6 | export default Food; 7 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/Tool.ts: -------------------------------------------------------------------------------- 1 | export default class Tools { 2 | // 重载无参无返回情况, 针对换行需求。 3 | static Log(): void; 4 | // 重载单一参数,有返回 5 | static Log(data: any): string; 6 | // 重载函数体: 参数是可选参数 7 | static Log(data?: any): string { 8 | if (data) { 9 | const dataStr = JSON.stringify(Object(data), null, 4) 10 | console.log(); 11 | console.log(dataStr); 12 | return dataStr; 13 | } else { 14 | console.log(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TS/code/polymorphism/src/main.ts: -------------------------------------------------------------------------------- 1 | import Breeder from './Breeder'; 2 | import Tool from './Tool'; 3 | 4 | import Fish from './Food/Fish'; 5 | import Bone from './Food/Bone'; 6 | import DogFood from './Food/DogFood'; 7 | 8 | import Dog from './Animal/Dog'; 9 | import Cat from './Animal/Cat'; 10 | 11 | class BreederManager { 12 | private _breeder: Breeder = new Breeder(); 13 | 14 | 15 | 16 | 17 | async main() { 18 | await this.testOne(); 19 | await this.testTwo(); 20 | await this.testThree(); 21 | } 22 | 23 | async testThree() { 24 | Tool.Log(); 25 | Tool.Log('----------------testThree---------------------'); 26 | const tom: Cat = new Cat('Tom'); 27 | const fish: Fish = new Fish('鱼', 25); 28 | await this._breeder.feed(tom, fish); 29 | } 30 | 31 | async testTwo() { 32 | Tool.Log(); 33 | Tool.Log('----------------testTwo---------------------'); 34 | const yelloDog: Dog = new Dog('黄狗'); 35 | const dogFood: DogFood = new DogFood('狗粮', 25); 36 | await this._breeder.feed(yelloDog, dogFood); 37 | 38 | Tool.Log('..........dev..........'); 39 | 40 | const bigBone: Bone = new Bone('小骨头', 50); 41 | await this._breeder.feed(yelloDog, bigBone); 42 | } 43 | 44 | async testOne() { 45 | Tool.Log(); 46 | Tool.Log('----------------testOne---------------------'); 47 | const xiaohuang: Dog = new Dog('小黄'); 48 | const smallBone: Bone = new Bone('小骨头', 25); 49 | await this._breeder.feed(xiaohuang, smallBone); 50 | 51 | Tool.Log('..........dev..........'); 52 | 53 | const dahuang: Dog = new Dog('大黄'); 54 | const bigBone: Bone = new Bone('大骨头', 50); 55 | await this._breeder.feed(dahuang, bigBone); 56 | 57 | Tool.Log('..........dev..........'); 58 | await this._breeder.feed(xiaohuang, bigBone); 59 | 60 | Tool.Log('..........dev..........'); 61 | await this._breeder.feed(dahuang, smallBone); 62 | } 63 | 64 | get breeder(): Breeder{ 65 | return this._breeder; 66 | } 67 | } 68 | 69 | new BreederManager().main(); 70 | -------------------------------------------------------------------------------- /TS/code/polymorphism/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitAny": true, 5 | "removeComments": true, 6 | "preserveConstEnums": true, 7 | "sourceMap": true, 8 | "target": "es2015" 9 | }, 10 | "include": [ 11 | "src/*" 12 | ], 13 | "exclude": [] 14 | } 15 | -------------------------------------------------------------------------------- /TS/code/service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "polymorphism", 3 | "version": "1.0.0", 4 | "description": "基本处理模型", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc --outdir ./build -w -t es2017 ./src/main.ts", 8 | "start": "node --experimental-modules --loader ~/.node.custom-loader.mjs build/main.js", 9 | 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "author": "", 13 | "license": "ISC" 14 | } 15 | -------------------------------------------------------------------------------- /TS/code/service/src/main.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/code/service/src/main.ts -------------------------------------------------------------------------------- /TS/code/service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitAny": true, 5 | "removeComments": true, 6 | "preserveConstEnums": true, 7 | "sourceMap": true, 8 | "target": "es2015" 9 | }, 10 | "include": [ 11 | "src/*" 12 | ], 13 | "exclude": [] 14 | } 15 | -------------------------------------------------------------------------------- /TS/code/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "jsx": "preserve", 5 | "experimentalDecorators": true, 6 | "emitDecoratorMetadata": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /TS/code/tsconfig/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "declarationDir": "dist", 6 | "declaration": true, 7 | "noImplicitAny": true, 8 | "removeComments": true, 9 | "preserveConstEnums": true, 10 | "sourceMap": true, 11 | "diagnostics": false, 12 | "traceResolution": false, 13 | "alwaysStrict": true, 14 | "strict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": true, 17 | "strictNullChecks": true, 18 | "strictPropertyInitialization": true, 19 | "resolveJsonModule": true, 20 | "pretty": true, 21 | "lib": ["es6"], 22 | "module": "commonjs", 23 | "types": ["node"] 24 | }, 25 | "files": [ 26 | "src/index.ts" 27 | ], 28 | "include": [ 29 | "./src/**/*", 30 | "./Typings/*.d.ts" 31 | ], 32 | "exclude": [ 33 | "node_modules", 34 | "bower_components", 35 | "jspm_packages", 36 | "**/*.spec.ts", 37 | "**/js-lib*" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /TS/code/update/update2.7/update.1.js: -------------------------------------------------------------------------------- 1 | // 运行命令: tsc --strictPropertyInitialization update.1.ts --strictNullChecks 2 | var C = /** @class */ (function () { 3 | // 显式赋值断言 4 | // baz!: boolean; 5 | // ~~~ 6 | // Error! Property 'baz' has no initializer and is not assigned directly in the constructor. 7 | function C() { 8 | this.bar = "hello"; 9 | this.foo = 42; 10 | this.initialize(); 11 | } 12 | C.prototype.initialize = function () { 13 | this.baz = true; 14 | }; 15 | return C; 16 | }()); 17 | console.log(new C()); 18 | -------------------------------------------------------------------------------- /TS/code/update/update2.7/update.1.ts: -------------------------------------------------------------------------------- 1 | // 运行命令: tsc --strictPropertyInitialization update.1.ts --strictNullChecks 2 | class C { 3 | foo: number; 4 | bar = "hello"; 5 | baz: boolean; 6 | // 显式赋值断言 7 | // baz!: boolean; 8 | 9 | // ~~~ 10 | // Error! Property 'baz' has no initializer and is not assigned directly in the constructor. 11 | constructor() { 12 | this.foo = 42; 13 | this.initialize(); 14 | } 15 | 16 | 17 | initialize() { 18 | this.baz = true; 19 | } 20 | } 21 | 22 | console.log(new C()); 23 | -------------------------------------------------------------------------------- /TS/code/update/update2.7/update.2.ts: -------------------------------------------------------------------------------- 1 | namespace up2 { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /TS/code/update/update2.8/update.1.ts: -------------------------------------------------------------------------------- 1 | type TypeName = 2 | T extends string ? "string" : 3 | T extends number ? "number" : 4 | T extends boolean ? "boolean" : 5 | T extends undefined ? "undefined" : 6 | T extends Function ? "function" : 7 | "object"; 8 | 9 | type T0 = TypeName; // "string" 10 | type T1 = TypeName<"a">; // "string" 11 | type T2 = TypeName; // "boolean" 12 | type T3 = TypeName<() => void>; // "function" 13 | type T4 = TypeName; // "object" 14 | -------------------------------------------------------------------------------- /TS/d.ts.md: -------------------------------------------------------------------------------- 1 | # d.ts 2 | -------------------------------------------------------------------------------- /TS/fileTypeChecking.md: -------------------------------------------------------------------------------- 1 | # javascript 文件类型检查 2 | 3 | > 文件类型检查 4 | 5 | 为什么要写到 js 中,然后用 TS 的很多特性? 不是很明白, 兼容老代码? 感觉只会让这文件四不像。这里梳理部分内容 6 | 7 | [javascript 文件类型检查](https://www.tslang.cn/docs/handbook/type-checking-javascript-files.html) 8 | 9 | --- 10 | 11 | TypeScript 2.3以后的版本支持使用--checkJs对.js文件进行类型检查和错误提示。因为本身是 js 文件,所以需要指定 `--outFile` 12 | 13 | 在 js 文件中 添加 `// @ts-check 开启类型检查和错误提示`, 执行如下编译命令即可对 js 进行类型检查和错误提示. 14 | 和 `// @ts-nocheck 忽略类型检查` 相反。 15 | 16 | ```sh 17 | tsc --allowJs ftc.1.ts --outFile ftc.1.ts.js 18 | ``` 19 | 20 | - 忽略本行的错误: `// @ts-ignore` 21 | 22 | 23 | --- 24 | 25 | ## .js文件和.ts文件在类型检查上的差异 26 | 27 | 1. 用JSDoc类型表示类型信息 28 | 29 | .js文件里,类型可以和在.ts文件里一样被推断出来。 同样地,当类型不能被推断时,它们可以通过JSDoc来指定,就好比在.ts文件里那样。 30 | 31 | ```javascript 32 | /** @type {number} */ 33 | var x; 34 | 35 | x = 0; // OK 36 | x = false; // Error: boolean is not assignable to number 37 | ``` 38 | 39 | 2. 属性的推断来自于类内的赋值语句 40 | 41 | ES2015没提供声明类属性的方法。属性是动态赋值的,就像对象字面量一样。 42 | 43 | ```js 44 | class C { 45 | constructor() { 46 | /** @type {number | undefined} */ 47 | this.prop = undefined; 48 | /** @type {number | undefined} */ 49 | this.count; 50 | } 51 | } 52 | 53 | let c = new C(); 54 | c.prop = 0; // OK 55 | c.count = "string"; // Error: string is not assignable to number|undefined 56 | ``` 57 | 58 | 省略部分内容 59 | 60 | 3. 对象字面量是开放的 61 | ```javascript 62 | var obj = { a: 1 }; 63 | obj.b = 2; // Allowed 64 | 65 | /** @type {{a: number}} */ 66 | var obj = { a: 1 }; 67 | obj.b = 2; // Error, type {a: number} does not have property b 68 | ``` 69 | 70 | 4. null,undefined,和空数组的类型是any或any[] 71 | 72 | 5. 函数参数是默认可选的 73 | ```javascript 74 | function bar(a, b) { 75 | console.log(a + " " + b); 76 | } 77 | 78 | bar(1); // OK, second argument considered optional 79 | bar(1, 2); 80 | bar(1, 2, 3); // Error, too many arguments 81 | ``` 82 | 83 | 84 | --- 85 | 86 | 87 | ## 支持的JSDoc 88 | 89 | - @type 90 | - @param (or @arg or @argument) 91 | - @returns (or @return) 92 | - @typedef 93 | - @callback 94 | - @template 95 | - @class (or @constructor) 96 | - @this 97 | - @extends (or @augments) 98 | - @enum 99 | 100 | 101 | #### @type 102 | 103 | 1. TS 中出现的类型,大多都可以出现在这里,包括类型转换【断言】 104 | ```js 105 | /** 106 | * @type {number | string} 107 | */ 108 | var numberOrString = Math.random() < 0.5 ? "hello" : 100; 109 | var typeAssertedNumber = /** @type {number} */ (numberOrString) 110 | ``` 111 | 112 | #### @param @returns 113 | ```js 114 | // Parameters may be declared in a variety of syntactic forms 115 | /** 116 | * @param {string} p1 - A string param. 117 | * @param {string=} p2 - An optional param (Closure syntax) 118 | * @param {string} [p3] - Another optional param (JSDoc syntax). 119 | * @param {string} [p4="test"] - An optional param with a default value 120 | * @return {string} This is the result 121 | */ 122 | function stringsStringStrings(p1, p2, p3, p4){ 123 | // TODO 124 | } 125 | ``` 126 | 127 | #### @template 128 | 129 | 使用@template声明泛型: 130 | 131 | 132 | 剩余部分参考: 133 | 134 | [javascript 文件类型检查](https://www.tslang.cn/docs/handbook/type-checking-javascript-files.html) 135 | -------------------------------------------------------------------------------- /TS/jsx.md: -------------------------------------------------------------------------------- 1 | # JSX 2 | 3 | > react 4 | 5 | ## 基本用法 6 | 7 | 前置条件 8 | 9 | - 给文件一个.tsx扩展名 10 | - 启用jsx选项: 你可以通过在命令行里使用--jsx标记或tsconfig.json里的选项来指定模式。 11 | 12 | TypeScript具有三种JSX模式:preserve,react和react-native。 这些模式只在代码生成阶段起作用 - 类型检查并不受影响。 13 | 14 | - preserve模式下生成代码中会保留JSX以供后续的转换操作使用(比如:Babel)。 另外,输出文件会带有.jsx扩展名。 15 | - react模式会生成React.createElement,在使用前不需要再进行转换操作了,输出文件的扩展名为.js。 16 | - react-native相当于preserve,它也保留了所有的JSX,但是输出文件的扩展名是.js。 17 | 18 | ![jsx1](../resource/img/jsx.1.png) 19 | 20 | jsx 这部分单独说明。 21 | -------------------------------------------------------------------------------- /TS/mixins.md: -------------------------------------------------------------------------------- 1 | # mixins 2 | 3 | > 混入: 代码复用。 4 | 5 | 但是一般来讲混入的对象之间不存在 is 的关系,也不是 has 的关系,就是一种单纯的代码复用,TS 中使用 implements 实现 mixins 总觉得有点别扭。 6 | 7 | TS 中很多比较基础,比较重要的语法,功能不够单一,会随着操作数的不同二产生不同的效果,我认为是非常不好的设计。比如 implements, 如果右操作数可以是接口,也可以是类。 extends 的左右操作数也一样。徒增复杂度,用起来也别扭。 8 | 9 | 还不采用如用 vue 类似的 mixins 语法。 10 | 11 | 12 | --- 13 | 14 | 基本思路: 15 | 16 | 1. 利用 implements 强制添加操作占位。 17 | 2. 利用成员方法挂在在 prototype 上, 于是批量覆盖替换. 18 | 3. 其实吧,implements 是多余的, 还带来类型的变化。 19 | 4. 总之这个特性实现的不好,用起来别扭。 20 | 21 | ```typescript 22 | // Disposable Mixin 23 | class Disposable { 24 | isDisposed: boolean; 25 | dispose() { 26 | this.isDisposed = true; 27 | } 28 | 29 | } 30 | 31 | // Activatable Mixin 32 | class Activatable { 33 | isActive: boolean; 34 | activate() { 35 | this.isActive = true; 36 | } 37 | deactivate() { 38 | this.isActive = false; 39 | } 40 | } 41 | 42 | class SmartObject implements Disposable, Activatable { 43 | constructor() { 44 | setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500); 45 | } 46 | 47 | interact() { 48 | this.activate(); 49 | } 50 | 51 | // 占位: 不可省略, 类似 implements 接口 52 | isDisposed: boolean = false; 53 | dispose: () => void; 54 | 55 | isActive: boolean = false; 56 | activate: () => void; 57 | deactivate: () => void; 58 | } 59 | applyMixins(SmartObject, [Disposable, Activatable]); 60 | 61 | let smartObj = new SmartObject(); 62 | setTimeout(() => smartObj.interact(), 1000); 63 | // 类型已经被覆盖: Activatable { isDisposed: false, isActive: false } 64 | console.log(smartObj); 65 | 66 | //////////////////////////////////////// 67 | // In your runtime library somewhere 68 | //////////////////////////////////////// 69 | function applyMixins(derivedCtor: any, baseCtors: any[]) { 70 | baseCtors.forEach(baseCtor => { 71 | Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { 72 | derivedCtor.prototype[name] = baseCtor.prototype[name]; 73 | }); 74 | }); 75 | } 76 | ``` 77 | -------------------------------------------------------------------------------- /TS/modifier.md: -------------------------------------------------------------------------------- 1 | # 修饰符 2 | 3 | ## 访问权限修饰符: 4 | `public[default], protect[子类], private` 5 | 6 | - 修饰作用: 参考 class.md [「访问权限修饰符」](./class.md) 章节 7 | 8 | - 修饰范围: 类成员(属性, 构造, 方法, __参数属性__)。不可修饰接口成员 9 | 10 | 参数属性: 【只允许在构造函数实现中使用参数属性。】 11 | 12 | > 参数属性是一种简化的写法。 13 | ```typescript 14 | // 如下是 public。 private, protected 同理。 15 | class P { 16 | constructor(public a: number) {} 17 | 18 | // error : 只允许在构造函数实现中使用参数属性。 19 | name(public a: number): void {} 20 | } 21 | new P(1).a; 22 | 23 | // 等价于 24 | class P1 { 25 | public a: number 26 | constructor(a: number) { 27 | this.a = a; 28 | } 29 | } 30 | new P(1).a; 31 | ``` 32 | 33 | 34 | ## 只读修饰符: 35 | `readonly` 36 | 37 | - 修饰作用: 只读 38 | 39 | - 修饰范围: 类, 接口属性. ["readonly" 修饰符仅可出现在属性声明或索引签名中。] 40 | 41 | - 注意点: 42 | - 只读属性必须在声明时或构造函数里被初始化。 43 | - readonly vs const: 最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly。 44 | 45 | - 只带有 get 不带有 set 的存取器自动被推断为 readonly 46 | 47 | 48 | ## 类修饰符 49 | 50 | 抽象类: `abstract` 51 | 52 | - 修饰作用: 参考 class.md [「抽象类」](./class.md) 章节 53 | 54 | 55 | ## static 56 | 57 | - 修饰作用: 参考 class.md [「静态成员」](./class.md) 章节 58 | 59 | - 修饰范围: 类, 接口属性. ["readonly" 修饰符仅可出现在属性声明或索引签名中。] 60 | 61 | - 注意点:静态成员可以被继承 62 | 63 | 64 | ## 泛型 65 | `` 66 | 67 | - 修饰作用: 延迟提供类型, 参考 [「泛型」](./generics.md) 68 | 69 | - 修饰范围: 类,接口,方法, 函数 70 | 71 | - 注意点: 72 | - 修饰类和接口时, 为类成员共有。 73 | - 不要乱用。用的时候理清楚抽象和实现。 74 | 75 | 76 | 77 | ## 模块化关键字 78 | 79 | 1. import 80 | 81 | 2. export 82 | - 修饰作用: 参考 module.md [「export」](./module.md) 章节 83 | - 修饰范围: 任何声明(比如变量,函数,类,类型别名或接口), 导出语句, 导出引入模块(export xx from 'xx/xx')。 84 | 85 | 86 | ## extends 87 | `class A extends B ...` 88 | 89 | - 修饰作用: 声明继承关系。需要两个操作数 90 | 91 | - 修饰范围:类/接口 和 类、抽象类、接口 之间描述继承关系【类实现接口】, 泛型约束: `` 92 | 93 | - 注意点:单继承 94 | 95 | 96 | ## implements 97 | `class A mplements classB { ... }` 98 | 99 | - 修饰作用: 实现,一般是实现抽象描述。 100 | 101 | - 修饰范围: 类实现接口, 类实现类【mixins】 参考 [mixins.md](./mixins.md) 章节 102 | 103 | - 注意点:多实现 104 | 105 | 106 | 107 | 108 | ---- 109 | 110 | 111 | ## 修饰符顺序 112 | 113 | 1. 访问权限修饰符 > static > 只读修饰符 => `private static readonly xx: any;` 114 | -------------------------------------------------------------------------------- /TS/namespace.md: -------------------------------------------------------------------------------- 1 | # namespace 2 | 3 | > 代码组织方案之一。 4 | > 适合处理那种不足以份文件维护的代码量。 5 | > 命名空间对解决全局作用域里命名冲突来说是很重要的 6 | 7 | --- 8 | 9 | 1. 基础语法 10 | ```typescript 11 | namespace xxx { 12 | // every thing of ts 13 | } 14 | ``` 15 | 16 | 2. 多 `namespace` 17 | 18 | - 单文件多 19 | 单个文件可以重复定义 namespace ,但是同名 namespace 之间的数据只要 export 了就可以直接在其他同名命名空间下使用。 20 | [namespace.1.ts](./code/namespace/namespace.1.ts) 21 | 22 | * 不推荐一个文件中存在多个同名命名空间。 23 | 24 | - 多个文件 25 | 多个文件里可以存在同名的 namespace ,通过 三斜线指令引用,可以使用其他文件的同名命名空间 export 的成员 26 | 27 | 注意: 1. 使用三斜线指令引入对应文件。 2. 需要收 28 | [namespace.1.js](./code/namespace/namespace.1.js) 29 | [namespace.1.ts](./code/namespace/namespace.1.ts) 30 | [namespace.2.ts](./code/namespace/namespace.2.ts) 31 | 32 | 33 | 3. namespace 别名: 场景不多,和 `import x = require...` 区分度不高。 34 | ```typescript 35 | namespace Shapes { 36 | export namespace Polygons { 37 | export class Triangle { } 38 | export class Square { } 39 | } 40 | } 41 | 42 | import polygons = Shapes.Polygons; 43 | let sq = new polygons.Square(); 44 | ``` 45 | 46 | 47 | --- 48 | 49 | 50 | ### __模块 & 命名空间__ 51 | 52 | 命名空间: 53 | - 命名空间组织代码,很难去识别组件之间的依赖关系,尤其是在大型的应用中。 54 | 55 | 模块: 56 | - 命名空间一样,模块可以包含代码和声明。 不同的是模块可以 声明它的依赖。 57 | - 模块会把依赖添加到模块加载器上(例如CommonJs / Require.js)。 对于小型的JS应用来说可能没必要,但是对于大型应用,这一点点的花费会带来长久的模块化和可维护性上的便利。 模块也提供了更好的代码重用,更强的封闭性以及更好的使用工具进行优化。 58 | 59 | 对于Node.js应用来说,模块是默认并推荐的组织代码的方式。 60 | 61 | 从ECMAScript 2015开始,模块成为了语言内置的部分,应该会被所有正常的解释引擎所支持。 因此,对于新项目来说推荐使用模块做为组织代码的方式 62 | 63 | 64 | #### 误区 65 | 66 | 1. 对模块使用/// 67 | 68 | 一个常见的错误是使用/// 引用模块文件,应该使用import. 69 | 70 | 2. 不必要的命名空间 71 | 72 | ```typescript 73 | export namespace Shapes { 74 | export class Triangle { /* ... */ } 75 | export class Square { /* ... */ } 76 | } 77 | ``` 78 | 79 | TypeScript里模块的一个特点是不同的模块永远也不会在相同的作用域内使用相同的名字。 因为使用模块的人会为它们命名,所以完全没有必要把导出的符号包裹在一个命名空间里。 80 | 81 | 请注意: 不应该对模块使用命名空间,使用命名空间是为了提供逻辑分组和避免命名冲突。 模块文件本身已经是一个逻辑分组,并且它的名字是由导入这个模块的代码指定,所以没有必要为导出的对象增加额外的模块层。 82 | 83 | 84 | 85 | ## 注意 86 | 1. TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。 87 | 2. 任何使用 module关键字来声明一个内部模块的地方都应该使用namespace关键字来替换。 这就避免了让新的使用者被相似的名称所迷惑。 88 | -------------------------------------------------------------------------------- /TS/readme.md: -------------------------------------------------------------------------------- 1 | # TypeScript 2 | 3 | > deno, angular/vue 高版本 ,白鹭... 越来越多的框架爱上 TS 4 | 5 | 🌀 高级特性: 6 | - 类型, 高级类型 7 | - 类型推断,类型兼容 8 | - 接口,类,抽象类 9 | - 成员访问权限控制 10 | - 命名空间 11 | - 模块,模块解析 12 | - 封装继承->多态 13 | - override 、 overload 14 | - 类似反射机制 15 | - 泛型 16 | - 装饰器 17 | - mixins 18 | - jsx 19 | 20 | ### [TS 基础部分: 类型,解构,声明...](./base.md) 21 | 22 | ### [TS 接口 interface](./interface.md) 23 | 24 | ### [TS class](./class.md) 25 | 26 | ### [__综合使用案例__](./code/polymorphism/src/) 27 | 28 | - [目录](./code/polymorphism/src/) 29 | - [入口](./code/polymorphism/src/main.ts) 30 | 31 | ### [TS function](./function.md) 32 | 33 | ### [泛型](./Generics.md) 34 | 35 | ### [高级类型](./advancedTypes.md) (小部分未完成) 36 | 37 | ### [module](./module.md) (小部分未完成) 38 | 39 | ### [namespace](./namespace.md) [模块和命名空间的取舍] 40 | 41 | ### [mixins](./mixins.md) 42 | 43 | ### [modifier](./modifier.md) 44 | 45 | ### [模块解析](./moduleResolution.md) (小部分未完成) 46 | 47 | ### [装饰器](./decorators.md) 48 | 49 | ### [javascript 文件类型检查](./fileTypeChecking.md) 50 | 51 | ### [update 2.7+](./update/readme.md) (跟进+补充) 52 | 53 | ### [声明文件](./d.ts.md) 54 | 55 | ### [配置文件](./tsconfig.md) 56 | 57 | --- 58 | 59 | ### [接入 & 迁移 & 构建](./TODO.md) 60 | ### [react](./TODO.md) 61 | 62 | 63 | [TODO](./TODO.md) 64 | 65 | 66 | --- 67 | 68 | ### 强调 69 | 70 | 1. TypeScript 使用的是结构性类型系统, 参考 base.md > 71 | [类型兼容性](./base.md##Type) 。 当我们比较两种不同的类型时,并不在乎它们从何处而来(类型是否匹配,或者存在与相同的继承关系),如果所有成员的类型都是兼容的,我们就认为它们的类型是兼容的。[demo](./code/class/class.9.ts) 72 | 2. 同一个属性的 get set 方法如果都存在,则访问修饰符必须一致,访问器装饰器声明在一个访问器的声明之前 73 | 3. 多态性:多种形态。 父类引用指向子类实例, 以父类为模板,以具体实现类的方法为实现【该引用中的成员以引用类型为准,指向的实现类扩展成员不可访问,实现以指向实例为准。多种状态】。 74 | 4. 接口声明的规范都是默认 公开 的, 不能使用访问修饰符修饰,包括 public,可以声明行为和属性。 75 | 5. instanceof 的右操作数必须是一个构造函数,接口抽象类都不行。 76 | 6. 接口可以继承类,包括 private 属性也能继承。 77 | 7. 类可以实现类,用以实现 mixins 78 | -------------------------------------------------------------------------------- /TS/tsconfig.md: -------------------------------------------------------------------------------- 1 | # tsconfig.json 2 | 3 | > tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项 4 | 5 | 6 | [配置示例](./code/tsconfig/tsconfig.json) 7 | 8 | 9 | - 编译选项: https://www.tslang.cn/docs/handbook/compiler-options.html 10 | - 错误信息参考: https://www.tslang.cn/docs/handbook/error.html 11 | - 构建工具集成: https://www.tslang.cn/docs/handbook/integrating-with-build-tools.html 12 | - 13 | -------------------------------------------------------------------------------- /TS/update/readme.md: -------------------------------------------------------------------------------- 1 | # update 更新特性梳理 2 | 3 | > 及时跟进更新 4 | 5 | 6 | ### TS2 - 2.6: [update info](./update-2.7-.md) 7 | 8 | ### TS2.7: [update info](./update-2.7.md) 9 | 10 | ### TS2.8: [update info](./update-2.8.md) 11 | 12 | TODO 13 | 14 | ### TS2.9: [update info](./update-2.9.md) 15 | 16 | ### TS3.0: [update info](./update-3.0.md) 17 | 18 | ### TS3.1: [update info](./update-3.1.md) 19 | -------------------------------------------------------------------------------- /TS/update/update-2.7-.md: -------------------------------------------------------------------------------- 1 | # TS2.7- 版本部分重要特性梳理 2 | 3 | ### [TS2.6](https://www.tslang.cn/docs/release-notes/typescript-2.6.html) 4 | 5 | 1. 严格函数类型 6 | 2. 通过 '// @ts-ignore' 注释隐藏 .ts 文件中的错误 7 | 8 | 9 | ### TS2.5 10 | 11 | ... 12 | 13 | ### TS2.4 14 | 15 | 1. 支持字符串枚举值 16 | 17 | 2. 动态导入表达式: 没成功 18 | ```typescript 19 | async function getZipFile(name: string, files: File[]): Promise { 20 | const zipUtil = await import('./utils/create-zip-file'); 21 | const zipContents = await zipUtil.getContentAsBlob(files); // error 22 | return new File(zipContents, name); 23 | } 24 | ``` 25 | 26 | ### TS2.3 27 | 28 | 1. 迭代器和生成器支持: Iterator, Generator. 引入 AsyncIterator 29 | 30 | ```typescript 31 | interface AsyncIterator { 32 | next(value?: any): Promise>; 33 | return?(value?: any): Promise>; 34 | throw?(e?: any): Promise>; 35 | } 36 | ``` 37 | 38 | 2. 异步生成器 39 | 40 | ```typescript 41 | async function* g() { 42 | yield 1; 43 | await sleep(100); 44 | yield* [2, 3]; 45 | yield* (async function *() { 46 | await sleep(100); 47 | yield 4; 48 | })(); 49 | } 50 | ``` 51 | 52 | 3. 异步可迭代对象迭代器: for-await-of。 53 | 54 | ES2015引入了for..of语句来迭代可迭代对象。相似的,异步迭代提案引入了for..await..of语句来迭代可异步迭代的对象。 55 | 56 | ```typescript 57 | async function f() { 58 | for await (const x of g()) { 59 | console.log(x); 60 | } 61 | } 62 | ``` 63 | 64 | 4. 泛型参数默认类型 65 | 66 | ```typescript 67 | declare function create(element?: T, children?: U): Container; 68 | ``` 69 | 70 | 5. --checkJS选项下 .js 文件中的错误 71 | 72 | 即便使用了--allowJs,TypeScript编译器默认不会报 .js 文件中的任何错误。TypeScript 2.3 中使用--checkJs选项,.js文件中的类型检查错误也可以被报出. 73 | 74 | 你可以通过为它们添加// @ts-nocheck注释来跳过对某些文件的检查,反过来你也可以选择通过添加// @ts-check注释只检查一些.js文件而不需要设置--checkJs编译选项。你也可以通过添加// @ts-ignore到特定行的一行前来忽略这一行的错误. 75 | 76 | 77 | ### TS2.2 78 | 79 | 1. object类型 80 | 81 | TypeScript没有表示非基本类型的类型,即不是number | string | boolean | symbol | null | undefined的类型。一个新的object类型登场。 82 | 83 | ```typescript 84 | declare function create(o: object | null): void; 85 | ``` 86 | 87 | 2. 支持 new.target 88 | 89 | new.target元属性是ES2015引入的新语法。当通过new构造函数创建实例时,new.target的值被设置为对最初用于分配实例的构造函数的引用。如果一个函数不是通过new构造而是直接被调用,那么new.target的值被设置为undefined。 90 | 91 | 很多库里都会有一段代码判断用户的调用方式,通过 this instanceof 等判断调用方式是不是 new ,如果不是则将 `return new xxx(param)`,现在可以使用 `mew.target` 处理 92 | 93 | ```typescript 94 | function f() { 95 | if (new.target) { /* called via 'new' */ } 96 | } 97 | ``` 98 | 99 | 3. 新的jsx: react-native 100 | 101 | 102 | ### TS2.1 103 | 104 | 1. keyof和查找类型 105 | 106 | 在JavaScript中属性名称作为参数的API是相当普遍的,但是到目前为止还没有表达在那些API中出现的类型关系。 107 | 108 | 输入索引类型查询或keyof,索引类型查询keyof T产生的类型是T的属性名称。keyof T的类型被认为是string的子类型。 109 | 110 | ```typescript 111 | interface Person { 112 | name: string; 113 | age: number; 114 | location: string; 115 | } 116 | 117 | type K1 = keyof Person; // "name" | "age" | "location" 118 | type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ... 119 | type K3 = keyof { [x: string]: Person }; // string 120 | 121 | // ------------- 122 | 123 | function getProperty(obj: T, key: K) { 124 | return obj[key]; // 推断类型是T[K] 125 | } 126 | 127 | function setProperty(obj: T, key: K, value: T[K]) { 128 | obj[key] = value; 129 | } 130 | 131 | let x = { foo: 10, bar: "hello!" }; 132 | 133 | let foo = getProperty(x, "foo"); // number 134 | let bar = getProperty(x, "bar"); // string 135 | 136 | let oops = getProperty(x, "wargarbl"); // 错误!"wargarbl"不存在"foo" | "bar"中 137 | 138 | setProperty(x, "foo", "string"); // 错误!, 类型是number而非string 139 | 140 | ``` 141 | -------------------------------------------------------------------------------- /TS/update/update-2.7.md: -------------------------------------------------------------------------------- 1 | # TS 2.7 2 | 3 | 1. 更严格的类属性检查 4 | 5 | TypeScript 2.7引入了一个新的控制严格性的标记 --strictPropertyInitialization! 6 | 7 | 使用这个标记会确保类的每个实例属性都会在构造函数里或使用属性初始化器赋值。 在某种意义上,它会明确地进行从变量到类的实例属性的赋值检查 8 | 9 | [update2.7 1](../code/update/update2.7/update.1.ts) 10 | 11 | 使用如下运行命令,运行该文件: 12 | ```shell 13 | tsc --strictPropertyInitialization --strictNullChecks update.1.ts && node update.1.js 14 | ``` 15 | 16 | ```typescript 17 | class C { 18 | foo: number; 19 | bar = "hello"; 20 | baz: boolean; 21 | // ~~~ 22 | // Error! Property 'baz' has no initializer and is not assigned directly in the constructor. 23 | constructor() { 24 | this.foo = 42; 25 | } 26 | } 27 | ``` 28 | 29 | 30 | 2. 显式赋值断言 31 | 32 | 上述代码存在问题,某些场景下属性会被间接地初始化,这时候抛错是不应该的,此时我们应该显式赋值断言来告诉编译器。 33 | 34 | 显式赋值断言对声明普遍适用 35 | ```typescript 36 | class C { 37 | foo!: number; 38 | // ^ 39 | // Notice this exclamation point! 40 | // This is the "definite assignment assertion" modifier. 41 | constructor() { 42 | this.initialize(); 43 | } 44 | 45 | initialize() { 46 | this.foo = 0; 47 | } 48 | } 49 | ``` 50 | 51 | 52 | 3. 更便利的与ECMAScript模块的互通性 53 | 54 | 供了一个新的编译选项 --esModuleInterop, 如果你使用Babel,Webpack或React Native,并期望与你以往使用地不同的导入行为。 【ECMAScript模块在ES2015里才被标准化,在这之前,JavaScript生态系统里存在几种不同的模块 格式,它们工作方式各有不同】 55 | 56 | 参考:[更便利的与ECMAScript模块的互通性](https://www.tslang.cn/docs/release-notes/typescript-2.7.html) 57 | 58 | 59 | 60 | 4. unique symbol类型和常量名属性 61 | 62 | unique symbols是 symbols的子类型,仅可通过调用 Symbol()或 Symbol.for()或由明确的类型注释生成。 它们仅出现在常量声明和只读的静态属性上,并且为了引用一个存在的 unique symbols类型,你必须使用 typeof操作符。 每个对 unique symbols的引用都意味着一个完全唯一的声明身份。 63 | 64 | ```typescript 65 | const Foo = Symbol("Foo"); 66 | const Bar = Symbol("Bar"); 67 | 68 | let x = { 69 | [Foo]: 100, 70 | [Bar]: "hello", 71 | }; 72 | 73 | let a = x[Foo]; // has type 'number' 74 | let b = x[Bar]; // has type 'string' 75 | ``` 76 | 77 | TypeScript可以追踪到 x拥有使用符号 Foo和 Bar声明的属性,因为 Foo和 Bar被声明成常量。 TypeScript利用了这一点,让 Foo和 Bar具有了一种新类型: unique symbols。 78 | 79 | 80 | 5. --watch模式下具有更简洁的输出. 更漂亮的 --pretty输出 81 | 82 | - --watch模式下进行重新编译后会清屏 83 | - --pretty标记可以让错误信息更易阅读和管理 84 | 85 | 86 | 6. 数字分隔符 87 | 88 | TypeScript 2.7支持ECMAScript的数字分隔符提案。 这个特性允许用户在数字之间使用下划线(_)来对数字分组(就像使用逗号和点来对数字分组那样)。 89 | 90 | ```typescript 91 | // Constants 92 | const a = 8.957_551_787e9; // N-m^2 / C^2 93 | const b = 6.626_070_040e-34; // J-s 94 | const c = 867_5309; // C-A-L^2 95 | 96 | // 二进制,十六进制 97 | let d = 0b0010_1010; 98 | let e = 0xC0FFEE_F00D_BED; 99 | let f = 0xF0_1E; 100 | 101 | console.log(a, b, c, d, e, f); 102 | // 8957551787 6.62607004e-34 8675309 42 3395287326448621 61470 103 | ``` 104 | 105 | 106 | 7. 固定长度元组 107 | 108 | TypeScript 2.6之前, [number, string, string]被当作 [number, string]的子类型。 这是由于TypeScript的结构性类型系统而造成的, 然而却忽略了元祖组长度的问题。 109 | 110 | 元组类型会考虑它的长度,不同长度的元组不再允许相互赋值。 它通过数字字面量类型实现,因此现在可以区分出不同长度的元组了。 111 | 112 | 113 | 8. in操作符细化和精确的 instanceof 114 | 115 | instanceof操作符现在利用继承链而非依赖于结构兼容性, 能更准确地反映出 instanceof操作符在运行时的行为。 这可以帮助避免一些复杂的问题,当使用 instanceof去细化结构上相似(但无关)的类型时。 116 | 117 | in操作符现在做为类型保护使用,会细化掉没有明确声明的属性名。 118 | 119 | ```typescript 120 | interface A { a: number }; 121 | interface B { b: string }; 122 | 123 | function foo(x: A | B) { 124 | if ("a" in x) { 125 | return x.a; 126 | } 127 | return x.b; 128 | } 129 | ``` 130 | 131 | 132 | 9. 更智能的对象字面量推断 133 | 134 | 对于 `let foo = someTest ? { value: 42 } : {};` 来讲, TypeScript会查找 { value: number }和 {}的最佳超类型,结果是 {}. 135 | 136 | 从2.7版本开始,TypeScript会“规范化”每个对象字面量类型记录每个属性, 为每个 undefined类型属性插入一个可选属性,并将它们联合起来。 137 | 138 | foo的最类型是 { value: number } | { value?: undefined } 139 | -------------------------------------------------------------------------------- /TS/update/update-2.8.md: -------------------------------------------------------------------------------- 1 | # [TS 2.8](https://www.tslang.cn/docs/release-notes/typescript-2.8.html) 2 | 3 | 1. 有条件类型: `T extends U ? X : Y` 4 | 5 | 请注意: 上面的类型意思是,若T能够赋值给U,那么类型是X,否则为Y。所以等价为: `(T extends U) ? X : Y` 6 | 7 | ```typescript 8 | type TypeName = 9 | T extends string ? "string" : 10 | T extends number ? "number" : 11 | T extends boolean ? "boolean" : 12 | T extends undefined ? "undefined" : 13 | T extends Function ? "function" : 14 | "object"; 15 | 16 | type T0 = TypeName; // "string" 17 | type T1 = TypeName<"a">; // "string" 18 | type T2 = TypeName; // "boolean" 19 | type T3 = TypeName<() => void>; // "function" 20 | type T4 = TypeName; // "object" 21 | ``` 22 | 23 | 2. 预定义的有条件类型 24 | 25 | TypeScript 2.8在lib.d.ts里增加了一些预定义的有条件类型: 26 | 27 | - Exclude -- 从T中剔除可以赋值给U的类型。 28 | - Extract -- 提取T中可以赋值给U的类型。 29 | - NonNullable -- 从T中剔除null和undefined。 30 | - ReturnType -- 获取函数返回值类型。 31 | - InstanceType -- 获取构造函数类型的实例类型。 32 | 33 | [code](../code/update/update2.8/update.1.ts) 34 | 35 | 36 | 3. 改进对映射类型修饰符的控制 37 | 38 | 映射类型支持在属性上添加readonly或?修饰符,但是它们不支持移除修饰符。 这对于同态映射类型有些影响,因为同态映射类型默认保留底层类型的修饰符。 39 | 40 | TypeScript 2.8为映射类型增加了增加或移除特定修饰符的能力。 特别地,映射类型里的readonly或?属性修饰符现在可以使用+或-前缀,来表示修饰符是添加还是移除。 41 | 42 | ```typescript 43 | type MutableRequired = { -readonly [P in keyof T]-?: T[P] }; // 移除readonly和? 44 | type ReadonlyPartial = { +readonly [P in keyof T]+?: T[P] }; // 添加readonly和? 45 | ``` 46 | 47 | 4. 改进交叉类型上的keyof 48 | 49 | TypeScript 2.8作用于交叉类型的keyof被转换成作用于交叉成员的keyof的联合。 换句话说,keyof (A & B)会被转换成keyof A | keyof B。 这个改动应该能够解决keyof表达式推断不一致的问题。 50 | 51 | ```typescript 52 | type A = { a: string }; 53 | type B = { b: string }; 54 | 55 | type T1 = keyof (A & B); // "a" | "b" 56 | type T2 = keyof (T & B); // keyof T | "b" 57 | type T3 = keyof (A & U); // "a" | keyof U 58 | type T4 = keyof (T & U); // keyof T | keyof U 59 | type T5 = T2; // "a" | "b" 60 | type T6 = T3; // "a" | "b" 61 | type T7 = T4; // "a" | "b" 62 | ``` 63 | 64 | 5. 原型赋值 65 | 66 | 你可以把一个对象字面量直接赋值给原型属性。独立的原型赋值也可以: 67 | 68 | ```typescript 69 | var C = function (p) { 70 | this.p = p; 71 | }; 72 | C.prototype = { 73 | m() { 74 | console.log(this.p); 75 | } 76 | }; 77 | C.prototype.q = function(r) { 78 | return this.p === r; 79 | }; 80 | ``` 81 | -------------------------------------------------------------------------------- /TS/update/update-2.9.md: -------------------------------------------------------------------------------- 1 | # [TS 2.9](https://www.tslang.cn/docs/release-notes/typescript-2.9.html) 2 | 3 | 1. keyof和映射类型支持用number和symbol命名的属性 4 | 5 | TypeScript 2.9增加了在索引类型和映射类型上支持用number和symbol命名属性。 在之前,keyof操作符和映射类型只支持string命名的属性。 6 | -------------------------------------------------------------------------------- /TS/update/update-3.0.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/update/update-3.0.md -------------------------------------------------------------------------------- /TS/update/update-3.1.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/TS/update/update-3.1.md -------------------------------------------------------------------------------- /algorithm/leecode/lee1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个整数数组和一个目标值, 找出数组中和为目标值的两个数。 3 | 4 | 你可以假设每个输入只对应一种答案, 且同样的元素不能被重复利用。 5 | 6 | 示例: 7 | 8 | 给定 nums = [2, 7, 11, 15], target = 9 9 | 10 | 因为 nums[0] + nums[1] = 2 + 7 = 9 11 | 所以返回[0, 1] 12 | */ 13 | 14 | function twoSum (nums, target) { 15 | const reMap = {}; 16 | 17 | for (let index = 0; index < nums.length; index++) { 18 | const cur = nums[index]; 19 | 20 | if(reMap[target - cur] >= 0) { 21 | return [reMap[target - cur], index] 22 | } else { 23 | reMap[cur] = index; 24 | } 25 | } 26 | } 27 | 28 | const nums = [1, 2, 4, 8, 12]; 29 | const target = 12 30 | 31 | const ts1 = twoSum(nums, target); 32 | console.log(ts1, '->', [nums[ts1[0]], nums[ts1[1]]]); 33 | 34 | 35 | /** 36 | * 上述算法由输出下标, 改为输出结果 37 | */ 38 | 39 | function twoSum1(nums, target) { 40 | const reMap = {}; 41 | 42 | for (let index = 0; index < nums.length; index++) { 43 | const cur = nums[index]; 44 | 45 | if (typeof reMap[cur] !== 'undefined') { 46 | return [reMap[cur], cur]; 47 | } else { 48 | reMap[target - cur] = cur; 49 | } 50 | } 51 | } 52 | 53 | const ts2 = twoSum1(nums, target); 54 | console.log(ts2); 55 | 56 | 57 | /** 58 | * leecode 耗时最少解法 59 | * @param {number[]} nums 60 | * @param {number} target 61 | * @return {number[]} 62 | */ 63 | var twoSum3 = function(nums, target) { 64 | 65 | var map = {}; 66 | for(var i = 0 ; i < nums.length ; i++){ 67 | var v = nums[i]; 68 | 69 | if(map[target-v] >= 0){ 70 | // 如果 target - v可以在map中找到值x,代表之前已经出现过的值x, target = x + v 71 | // 因此回传x的位置与目前v的位置 72 | return [map[target-v],i] 73 | } else { 74 | // 使用map储存目前的数字与其位置 75 | 76 | map[v] = i; 77 | } 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /algorithm/leecode/lee118.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个非负整数 numRows, 生成杨辉三角的前 numRows 行。 3 | * https: //upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif 4 | * 5 | * 输入: 5 6 | * 输出: [ 7 | * [1], 8 | * [1, 1], 1: 1,0 1: 1,1 9 | * [1, 2, 1], 10 | * [1, 3, 3, 1], 11 | * [1, 4, 6, 4, 1] 4: 4,1 = 3,0 + 3,1 6: 4,2 = 3,1 + 3,2 12 | * ] 13 | * 14 | * 我的提交执行用时 15 | * 已经战胜 97.78 % 的 javascript 提交记录 16 | */ 17 | 18 | function generate(numRows) { 19 | if (numRows < 1) { 20 | return []; 21 | } 22 | const genArr = [[1]]; 23 | for (let i = 1; i < numRows; i++) { 24 | genArr[i] = []; 25 | for (let j = 0; j <= i; j++) { 26 | genArr[i][j] = (genArr[i - 1][j - 1] || 0) + (genArr[i - 1][j] || 0) 27 | } 28 | } 29 | 30 | return genArr; 31 | } 32 | 33 | const yh5 = generate(5); 34 | 35 | console.log(JSON.stringify(yh5, null, 4)); 36 | 37 | 38 | /** 39 | * leecode 耗时最少解法 40 | * @param {number} numRows 41 | * @return {number[][]} 42 | */ 43 | let generate = function (numRows) { 44 | if (numRows === 0) return []; 45 | if (numRows === 1) return [ 46 | [1] 47 | ]; 48 | let arr = [ 49 | [1] 50 | ]; 51 | for (let i = 1; i < numRows; ++i) { 52 | let row = [1]; 53 | for (let j = 1; j < arr[i - 1].length; ++j) { 54 | row.push(arr[i - 1][j - 1] + arr[i - 1][j]) 55 | } 56 | row.push(1); 57 | arr.push(row); 58 | } 59 | return arr; 60 | }; 61 | -------------------------------------------------------------------------------- /algorithm/leecode/lee119.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 在杨辉三角中, 每个数是它左上方和右上方的数的和。 3 | * 4 | * 示例: 5 | * 6 | * 输入: 3 7 | * 输出: [1, 3, 3, 1] 8 | * 进阶: 9 | * 10 | * 你可以优化你的算法到 O(k) 空间复杂度吗? 11 | */ 12 | 13 | function genRow(rowIndex) { 14 | if (rowIndex < 0) { 15 | return []; 16 | } 17 | let row = [1]; 18 | for (let i = 1; i < rowIndex + 1; i++) { 19 | let temp = [1]; 20 | for (let j = 0; j <= i; j++) { 21 | temp[j] = (row[j - 1] || 0) + (row[j] || 0) 22 | } 23 | row = temp; 24 | } 25 | 26 | return row; 27 | } 28 | 29 | 30 | /** 31 | * leecode 耗时最少解法 32 | * @param {*} nums 33 | * @param {*} target 34 | */ 35 | function leeGenRow(k) { 36 | let results = Array(k + 1).fill(1) 37 | for (let i = 0; i < k + 1; i++) { 38 | for (let j = i - 1; j >= 1; j--) { 39 | console.log(i, j, results); 40 | results[j] = results[j] + results[j - 1] 41 | } 42 | } 43 | return results 44 | } 45 | 46 | // console.log(genRow(4)); 47 | console.log(leeGenRow(4)); 48 | -------------------------------------------------------------------------------- /algorithm/leecode/lee136.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个非空整数数组, 除了某个元素只出现一次以外, 其余每个元素均出现两次。 找出那个只出现了一次的元素。 3 | 4 | 说明: 5 | 6 | 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 7 | 8 | 示例 1: 9 | 10 | 输入: [2, 2, 1] 11 | 输出: 1 12 | 示例 2: 13 | 14 | 输入: [4, 1, 2, 1, 2] 15 | 输出: 4 16 | */ 17 | 18 | /** 19 | * @param {number[]} nums 20 | * @return {number} 21 | * 22 | * 首先 a ^ a = 0, a ^ 0 = a. 23 | * 我们将数组展开 a1 ^ a2 ^ ... a11 ^ a22 ^ an[假设 a1 === a11], 通过交换律得到 24 | * (a1 ^ a11) ^ (a2 ^ a22)...则结果 0 ^ aTarget = aTarget 25 | */ 26 | var singleNumber = function (nums) { 27 | let sum = nums[0]; 28 | for (let i = 1; i < nums.length; i ++) { 29 | sum ^= nums[i]; 30 | } 31 | 32 | return sum; 33 | }; 34 | 35 | const re = singleNumber([4, 1, 2, 1, 2]); 36 | 37 | console.log(re); 38 | 39 | 40 | /** 41 | * leecode 耗时最少解法 42 | * @param {*} nums 43 | */ 44 | var singleNumber = function (nums) { 45 | return nums.reduce(function (pre, cur) { 46 | return pre ^ cur; 47 | }) 48 | }; 49 | 50 | /** 51 | * @param {number[]} nums 52 | * @return {number} 53 | */ 54 | var singleNumber = function (nums) { 55 | let init = 0 56 | nums.forEach(d => { 57 | init ^= d 58 | }) 59 | return init 60 | }; 61 | -------------------------------------------------------------------------------- /algorithm/leecode/lee14.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 最长公共前缀 3 | * [ 4 | * 'a b c' 5 | * 'a b d' 6 | * 'a b f' 7 | * 'a b c d' 8 | * ] 9 | * 10 | * 思路: 将这个字符串数组看做二维数组.我们外层无限循环, 因为不知道最短的字符串 11 | */ 12 | 13 | function longestCommonPrefix(strs = []) { 14 | let i = 0 15 | if (strs.length < 2) { 16 | return strs[0] || '' 17 | } 18 | while(true) { 19 | for (let j = 1; j < strs.length; j++) { 20 | debugger; 21 | if (strs[0][i] !== strs[j][i] || strs[0].length === i || strs[j].length === i) { 22 | return strs[0].substring(0, i); 23 | } 24 | } 25 | i++; 26 | } 27 | return strs[0].substring(0, i); 28 | } 29 | 30 | console.log(longestCommonPrefix(['abdd', 'abdww', 'abdcdd'])) 31 | 32 | 33 | /** 34 | * leecode 耗时最少解法 35 | * @param {string[]} strs 36 | * @return {string} 37 | */ 38 | var longestCommonPrefix = function (strs) { 39 | if (strs.length == 0) return ""; 40 | let prefix = strs[0]; 41 | for (let i = 1; i < strs.length; i++) 42 | while (strs[i].indexOf(prefix) != 0) { 43 | prefix = prefix.substring(0, prefix.length - 1); 44 | if (prefix.length == 0) return ""; 45 | } 46 | return prefix; 47 | }; 48 | -------------------------------------------------------------------------------- /algorithm/leecode/lee169.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个大小为 n 的数组, 找到其中的众数。 众数是指在数组中出现次数大于⌊ n / 2⌋ 的元素。 3 | 4 | 你可以假设数组是非空的, 并且给定的数组总是存在众数。 5 | 6 | 输入: [2, 2, 1, 1, 1, 2, 2] 7 | 输出: 2 8 | 9 | 注意一个数组中不可能有多个众数, 因为众数个数大于一半 10 | 11 | */ 12 | 13 | /** 14 | * @param {number[]} nums 15 | * @return {number} 16 | * 我的提交执行用时 17 | 已经战胜 84.33 % 的 javascript 提交记录 18 | */ 19 | var majorityElement = function (nums) { 20 | const countList = {}; 21 | const len = nums.length; 22 | 23 | for(let i = 0; i < len; i ++) { 24 | const cur = nums[i]; 25 | countList[cur] = countList[cur] + 1 || 1; 26 | 27 | if (countList[cur] > len / 2) { 28 | return cur; 29 | } 30 | } 31 | }; 32 | 33 | 34 | const re = majorityElement([1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 2]); 35 | console.log(re); 36 | 37 | 38 | /** 39 | * leecode 耗时最少解法 40 | * @param {number[]} nums 41 | * @return {number} 42 | */ 43 | 44 | // [1, 2, 1, 2, 1, 2, 2]; 45 | let majorityElement = function (nums) { 46 | let count = 0; 47 | let candidate = 0; 48 | for (let num of nums) { 49 | if (count === 0) { 50 | candidate = num; // 1 51 | } 52 | 53 | // 思路很巧妙,此题限定众数一定存在,所以众数的个数比其他所有数的和都多。 54 | // 所以我们假设将众数和其他数间隔排布,一个众数抵消一个其他数字, 最后一定剩下的是众数。 55 | // 但是这种算法不稳定,一定会将数组遍历结束,假设某个数组长度为 n, 其中 n-1 个数是 m, 56 | // 此时我们只需要遍历 n / 2 + 1 次就能找到众数。 57 | count = candidate === num ? count + 1 : count - 1; 58 | } 59 | return candidate; 60 | }; 61 | 62 | /* 63 | let majorityElement = function(nums) { 64 | let map = {}; 65 | for (let num of nums) { 66 | map[num] = map[num] + 1 || 1; 67 | if (map[num] > nums.length / 2) { 68 | return num; 69 | } 70 | } 71 | }; 72 | */ 73 | 74 | 75 | /** 76 | * 优化, 这种优化针对很特殊的数据. [1, 2, 2, 2, 2, 2, 2, .... , 2] 77 | * @param {*} nums 78 | */ 79 | let majorityElement = function (nums) { 80 | let count = 0; 81 | let candidate = 0; 82 | let len = nums.length; 83 | for (let i = 0; i < len; i ++) { 84 | if (count === 0) { 85 | candidate = nums[i]; // 1 86 | } 87 | count = candidate === nums[i] ? count + 1 : count - 1; 88 | 89 | if(count > len / 2) { 90 | return candidate; 91 | } 92 | } 93 | return candidate; 94 | }; 95 | -------------------------------------------------------------------------------- /algorithm/leecode/lee189.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个数组, 将数组中的元素向右移动 k 个位置, 其中 k 是非负数。 3 | 4 | 示例 1: 5 | 6 | 输入: [1, 2, 3, 4, 5, 6, 7] 和 k = 3 7 | 输出: [5, 6, 7, 1, 2, 3, 4] 8 | 解释: 9 | 向右旋转 1 步: [7, 1, 2, 3, 4, 5, 6] 10 | 向右旋转 2 步: [6, 7, 1, 2, 3, 4, 5] 11 | 向右旋转 3 步: [5, 6, 7, 1, 2, 3, 4] 12 | 示例 2: 13 | 14 | 输入: [-1, -100, 3, 99] 和 k = 2 15 | 输出: [3, 99, -1, -100] 16 | 解释: 17 | 向右旋转 1 步: [99, -1, -100, 3] 18 | 向右旋转 2 步: [3, 99, -1, -100] 19 | 说明: 20 | 21 | 尽可能想出更多的解决方案, 至少有三种不同的方法可以解决这个问题。 22 | 要求使用空间复杂度为 O(1) 的原地算法。 23 | */ 24 | 25 | 26 | /** 27 | * leecode 耗时最少解法 28 | * @param {number[]} nums 29 | * @param {number} k 30 | * @return {void} Do not return anything, modify nums in-place instead. 31 | */ 32 | var rotate = function (nums, k) { 33 | nums.unshift(...nums.splice(nums.length - k)); 34 | } 35 | 36 | let x = [1, 2, 3, 4, 5, 6, 7]; 37 | const re = rotate(x, 3); 38 | 39 | console.log(x); 40 | 41 | 42 | /** 43 | * other 44 | * @param {number[]} nums 45 | * @param {number} k 46 | * @return {void} Do not return anything, modify nums in-place instead. 47 | */ 48 | var rotate = function (nums, k) { 49 | k %= nums.length; 50 | reverse(nums, 0, nums.length - 1); 51 | reverse(nums, 0, k - 1); 52 | reverse(nums, k, nums.length - 1); 53 | }; 54 | 55 | function reverse(nums, start, end) { 56 | while (start < end) { 57 | let temp = nums[start]; 58 | nums[start] = nums[end]; 59 | nums[end] = temp; 60 | start++; 61 | end--; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /algorithm/leecode/lee190.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | 颠倒给定的 32 位无符号整数的二进制位。 4 | 5 | 示例: 6 | 7 | 输入: 43261596 8 | 输出: 964176192 9 | 解释: 43261596 的二进制表示形式为 00000010100101000001111010011100, 10 | 返回 964176192, 其二进制表示形式为 00111001011110000010100101000000。 11 | 进阶: 12 | 如果多次调用这个函数, 你将如何优化你的算法? 13 | */ 14 | 15 | 16 | /** 17 | * @param {number} n - a positive integer 18 | * @return {number} - a positive integer 19 | * 利用 & 1 找出 为 1 的二进制位。 20 | * 计算其 21 | */ 22 | var reverseBits = function (n) { 23 | let reNum = 0; 24 | let len = 32; 25 | while (len --) { 26 | // console.log(reNum, n & 1, len); 27 | reNum += 2 ** len * (n & 1) 28 | 29 | n = n >>> 1; 30 | } 31 | return reNum; 32 | }; 33 | 34 | const re = reverseBits(43261596); 35 | 36 | console.log(re); 37 | 38 | 39 | 40 | /** 41 | * leecode 耗时最少解法 42 | * @param {number} n - a positive integer 43 | * @return {number} - a positive integer 44 | */ 45 | let reverseBits = function (n) { 46 | n = (n >>> 16) | (n << 16); 47 | n = (n >>> 8 & 0x00ff00ff) | (n << 8 & 0xff00ff00); 48 | n = (n >>> 4 & 0x0f0f0f0f) | (n << 4 & 0xf0f0f0f0); 49 | n = (n >>> 2 & 0x33333333) | (n << 2 & 0xcccccccc); 50 | n = (n >>> 1 & 0x55555555) | (n << 1 & 0xaaaaaaaa); 51 | return n >>> 0; 52 | }; 53 | 54 | /* 55 | let reverseBits = function(n) { 56 | let res = 0; 57 | for (let i = 0; i < 32; i++) { 58 | res <<= 1; 59 | res |= n & 1; 60 | n >>= 1; 61 | } 62 | return res >>> 0; 63 | }; 64 | */ 65 | 66 | // >>> 0 convert to unsigned Number 67 | -------------------------------------------------------------------------------- /algorithm/leecode/lee191.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | 编写一个函数, 输入是一个无符号整数, 返回其二进制表达式中数字位数为‘ 1’ 的个数( 也被称为汉明重量)。 4 | 5 | 示例: 6 | 7 | 输入: 11 8 | 输出: 3 9 | 解释: 整数 11 的二进制表示为 00000000000000000000000000001011 10 | 11 | 12 | 示例 2: 13 | 14 | 输入: 128 15 | 输出: 1 16 | 解释: 整数 128 的二进制表示为 00000000000000000000000010000000 17 | 18 | */ 19 | 20 | 21 | /** 22 | * @param {number} n - a positive integer 23 | * @return {number} 24 | */ 25 | var hammingWeight = function (n) { 26 | let count = 0; 27 | while(n) { 28 | if(n & 1) { 29 | count ++; 30 | } 31 | 32 | n = n >>> 1; 33 | } 34 | return count; 35 | }; 36 | 37 | const re = hammingWeight(127); 38 | 39 | console.log(re); 40 | 41 | 42 | /** 43 | * leecode 耗时最少解法 44 | * @param {number} n - a positive integer 45 | * @return {number} 46 | */ 47 | var hammingWeight = function (n) { 48 | let res = 0; 49 | for (; n !== 0; n = n >>> 1) { 50 | res += n & 1 === 1 ? 1 : 0; 51 | } 52 | return res; 53 | }; 54 | -------------------------------------------------------------------------------- /algorithm/leecode/lee2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定两个非空链表来表示两个非负整数。 位数按照逆序方式存储, 它们的每个节点只存储单个数字。 将两数相加返回一个新的链表。 3 | 4 | 你可以假设除了数字 0 之外, 这两个数字都不会以零开头。 5 | 6 | 示例: 7 | 8 | 输入:(2 - > 4 - > 3) + (5 - > 6 - > 4) 9 | 输出: 7 - > 0 - > 8 10 | 原因: 342 + 465 = 807 11 | */ 12 | 13 | /** 14 | * Definition for singly-linked list. 15 | * function ListNode(val) { 16 | * this.val = val; 17 | * this.next = null; 18 | * } 19 | */ 20 | /** 21 | * @param {ListNode} l1 22 | * @param {ListNode} l2 23 | * @return {ListNode} 24 | */ 25 | function ListNode(val, next = null) { 26 | this.val = val; 27 | this.next = next; 28 | } 29 | 30 | const genNumLi = (num) => { 31 | if (num <= 0) { 32 | return null 33 | } 34 | const curNum = num % 10; 35 | const root = new ListNode(curNum); 36 | num = Math.floor(num / 10); 37 | 38 | let cur = root; 39 | while (num > 0) { 40 | const curNum = num % 10; 41 | cur.next = new ListNode(curNum); 42 | 43 | num = Math.floor(num / 10); 44 | cur = cur.next; 45 | } 46 | 47 | return root; 48 | } 49 | 50 | const [l1, l2] = [ 51 | genNumLi(99), 52 | genNumLi(10), 53 | ]; // 1245 54 | 55 | 56 | function addTwoNumbers(l1, l2) { 57 | let overflow = false; 58 | let cur1 = l1; 59 | let cur2 = l2; 60 | 61 | let temp = true 62 | while (cur1 !== null || cur2 !== null) { 63 | const sum = cur1.val + cur2.val + !!overflow; 64 | overflow = sum >= 10; 65 | cur1.val = sum % 10; 66 | cur2.val = sum % 10; 67 | 68 | // 如果不够进行补位 69 | temp = cur1.next || cur2.next; 70 | cur1 = cur1.next || (temp || overflow ? cur1.next = {val: 0} : null); 71 | cur2 = cur2.next || (temp || overflow ? cur2.next = {val: 0} : null); 72 | } 73 | 74 | return cur1 && l1 || cur2 && l2 || l1; 75 | } 76 | 77 | 78 | 79 | const li = addTwoNumbers(l1, l2); 80 | 81 | console.log(JSON.stringify(li)); 82 | 83 | 84 | /** 85 | * lee 耗时最少解法 86 | */ 87 | function addTwoNumbers(l1, l2) { 88 | let carry = 0; 89 | let result = new ListNode(); 90 | let resultNode = result; 91 | let l1val = l1.val; 92 | let l2val = l2.val; 93 | while (l1 || l2 || carry > 0) { 94 | l1val = l1 ? l1.val : 0; 95 | l2val = l2 ? l2.val : 0; 96 | resultNode.val = l1val + l2val + carry; 97 | carry = 0; 98 | if (resultNode.val >= 10) { 99 | resultNode.val = resultNode.val % 10; 100 | carry = 1; 101 | } 102 | l1 && (l1 = l1.next); 103 | l2 && (l2 = l2.next); 104 | if (l1 || l2 || carry > 0) { 105 | resultNode.next = new ListNode(); 106 | resultNode = resultNode.next; 107 | } 108 | } 109 | return result; 110 | } 111 | -------------------------------------------------------------------------------- /algorithm/leecode/lee231.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个整数, 编写一个函数来判断它是否是 2 的幂次方。 3 | 4 | 示例 1: 5 | 6 | 输入: 1 7 | 输出: true 8 | 解释: 20 = 1 9 | 示例 2: 10 | 11 | 输入: 16 12 | 输出: true 13 | 解释: 24 = 16 14 | 示例 3: 15 | 16 | 输入: 218 17 | 输出: false 18 | */ 19 | 20 | /** 21 | * @param {number} n 22 | * @return {boolean} 23 | */ 24 | var isPowerOfTwo = function (n) { 25 | return n > 0 && n.toString(2).match(/1/g).length === 1; 26 | }; 27 | 28 | 29 | /** 30 | * leecode 耗时最少解法 31 | * @param {number} n 32 | * @return {boolean} 33 | * 厉害了, 2**n 的二进制一定只有一个1, 34 | * 如果 n === 2 ** m ,那么 n & (n - 1) 一定是 - 35 | */ 36 | let isPowerOfTwo = function (n) { 37 | return n > 0 && !(n & (n - 1)); 38 | }; 39 | 40 | /* 41 | let isPowerOfTwo = function(n) { 42 | let oneNums = 0; 43 | for (; n > 0; n >>= 1) { 44 | oneNums += n & 1 === 1 ? 1 : 0; 45 | } 46 | return oneNums === 1; 47 | }; 48 | */ 49 | -------------------------------------------------------------------------------- /algorithm/leecode/lee258.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个非负整数 num, 反复将各个位上的数字相加, 直到结果为一位数。 3 | 4 | 示例: 5 | 6 | 输入: 38 7 | 输出: 2 8 | 解释: 各位相加的过程为: 3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数, 所以返回 2。 9 | 进阶: 10 | 你可以不使用循环或者递归, 且在 O(1) 时间复杂度内解决这个问题吗? 11 | */ 12 | 13 | /** 14 | * @param {number} num 15 | * @return {number} 16 | * 此题需要数学知识,反正我是一脸懵逼。 17 | * 18 | * https://www.zhihu.com/question/30972581 19 | 20 | 首先: 12345 = 1 * 9999 + 2 * 999 + 3 * 99 + 4 * 9 + 21 | 5 + (1 + 2 + 3 + 4 + 5) 只要证明: 12345 % 9 = (1 + 2 + 3 + 4 + 5) % 9 就能往下递推了。 那么, 我们已知: m % 9 = a; 22 | n % 9 = b 即 m = 9 * x + 23 | a; 24 | n = 9 * y + b; 可推出(m + n) % 9 = a + b = m % 9 + n % 9;[1 * 9999 + 2 * 999 + 3 * 99 + 4 * 9 + (1 + 25 | 2 + 3 + 4 + 5)] % 9 = (1 * 9999) % 9 + (2 * 999) % 9 + (3 * 99) % 9 + (4 * 9) % 26 | 9 + (1 + 2 + 3 + 4 + 5) % 9 = 0 + 0 + 0 + 0 + (1 + 2 + 3 + 4 + 5) % 9 = (1 + 2 + 27 | 3 + 4 + 5) % 9。 证明完成: 12345 % 9 = (1 + 2 + 3 + 4 + 5) % 9; 28 | 因为题中最后一个数恰好是小于10, 与取mod 9 结束也一致, 所以:(12345) % 9 = (1 + 2 + 3 + 4 + 5) % 9 = 12 % 29 | 9 = (1 + 2) % 9 = 3 % 9 = 3。 30 | */ 31 | var addDigits = function (num) { 32 | return (num - 1) % 9 + 1; 33 | }; 34 | 35 | 36 | const re = addDigits(1); 37 | console.log(re); 38 | 39 | 40 | /** 41 | * leecode 耗时最少解法 42 | * @param {number} num 43 | * @return {number} 44 | */ 45 | var addDigits = function (num) { 46 | if (num == 0) { 47 | return 0; 48 | } 49 | if (num % 9 == 0) { 50 | return 9; 51 | } else { 52 | return num % 9; 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /algorithm/leecode/lee268.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列, 找出 0..n 中没有出现在序列中的那个数。 3 | 4 | 示例 1: 5 | 6 | 输入: [3, 0, 1] 7 | 输出: 2 8 | 示例 2: 9 | 10 | 输入: [9, 6, 4, 2, 3, 5, 7, 0, 1] 11 | 输出: 8 12 | */ 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number} 17 | * 的提交执行用时 18 | 已经战胜 96.86 % 的 javascript 提交记录 19 | Runtime(ms) Distribution( % ) 20 | */ 21 | var missingNumber = function (nums) { 22 | let sum = nums[0]; 23 | const len = nums.length; 24 | for (let i = 1; i < len; i ++) { 25 | sum += nums[i]; 26 | } 27 | 28 | return (1 + len) * len / 2 - sum; 29 | }; 30 | 31 | 32 | const re = missingNumber([9, 6, 4, 2, 3, 8, 7, 0, 1]); 33 | 34 | console.log(re); 35 | 36 | 37 | /** 38 | * leecode 耗时最少解法 39 | * @param {number[]} nums 40 | * @return {number} 41 | */ 42 | let missingNumber = function (nums) { 43 | let res = 0; 44 | for (let i = 0; i <= nums.length; i++) { 45 | res ^= i ^ nums[i]; 46 | } 47 | return res; 48 | }; 49 | 50 | /* 51 | let missingNumber = function(nums) { 52 | let res = nums.length * (nums.length + 1) / 2; 53 | nums.forEach(num => res -= num); 54 | return res; 55 | }; 56 | */ 57 | -------------------------------------------------------------------------------- /algorithm/leecode/lee27.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 给定一个数组 nums 和一个值 val, 你需要原地移除所有数值等于 val 的元素, 返回移除后数组的新长度。 4 | * 不要使用额外的数组空间, 你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 5 | * 元素的顺序可以改变。 你不需要考虑数组中超出新长度后面的元素。 6 | * 7 | * 给定 nums = [0, 1, 2, 2, 3, 0, 4, 2], val = 2, 8 | * 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 9 | * 注意这五个元素可为任意顺序。 10 | * 你不需要考虑数组中超出新长度后面的元素。 11 | */ 12 | 13 | function removeElement(nums, val) { 14 | const len = nums.length 15 | let j = len - 1 16 | for (let i = 0; i < len;) { 17 | // 注意一个元素的时候 18 | if (i > j) { 19 | return i 20 | } 21 | if (nums[i] === val) { 22 | if (nums[j] !== val) { 23 | [nums[i], nums[j]] = [nums[j], nums[i]] 24 | } 25 | j -- 26 | } else { 27 | i++ 28 | } 29 | } 30 | return 0 31 | } 32 | 33 | const nums = [0] 34 | const len = removeElement(nums, 0) 35 | console.log(len, nums) 36 | 37 | 38 | /** 39 | * lee 最佳答案: 简化思路. 找到不等于 val 的数直接和当前游标交换. 40 | * @param {*} nums 41 | * @param {*} val 42 | */ 43 | function removeElement1(nums, val) { 44 | var j = 0 45 | for (i = 0; i < nums.length; i++) { 46 | if (nums[i] != val) { 47 | nums[j++] = nums[i] 48 | } 49 | } 50 | return j 51 | } -------------------------------------------------------------------------------- /algorithm/leecode/lee28.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 实现 strStr() 函数。 3 | * 4 | * 给定一个 haystack 字符串和一个 needle 字符串, 在 haystack 字符串中找出 needle 字符串出现的第一个位置(从0开始)。 如果不存在, 则返回 - 1。 5 | * 6 | * 示例 1: 7 | * 8 | * 输入: haystack = 'hello', needle = 'll' 9 | * 输出: 2 10 | * 示例 2: 11 | * 12 | * 输入: haystack = 'aaaaa', needle = 'bba' 13 | * 输出: -1 14 | * 说明: 15 | * 16 | * 当 needle 是空字符串时, 我们应当返回什么值呢? 这是一个在面试中很好的问题。 17 | * 18 | * 对于本题而言, 当 needle 是空字符串时我们应当返回 0。 这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 19 | */ 20 | 21 | function indexOf(haystack, needle) { 22 | if (needle === '') { 23 | return 0; 24 | } 25 | const needleLen = needle.length 26 | const haystackLen = haystack.length 27 | debugger 28 | if (needleLen > haystackLen) { 29 | return -1; 30 | } 31 | 32 | for (let i = 0; i < haystackLen - needleLen + 1; i++) { 33 | // console.log(haystack.substring(i, i + needleLen)); 34 | if (needle === haystack.substring(i, i + needleLen)) { 35 | return i; 36 | } 37 | } 38 | return -1; 39 | } 40 | 41 | console.log(indexOf('hello', 'lg')); 42 | 43 | 44 | /** 45 | * leecode 耗时最少解法 46 | * @param {string} haystack 47 | * @param {string} needle 48 | * @return {number} 49 | */ 50 | var strStr = function (haystack, needle) { 51 | if (needle == "") { 52 | return 0; 53 | } 54 | return haystack.indexOf(needle); 55 | }; 56 | -------------------------------------------------------------------------------- /algorithm/leecode/lee326.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个整数, 写一个函数来判断它是否是 3 的幂次方。 3 | 4 | 示例 1: 5 | 6 | 输入: 27 7 | 输出: true 8 | 示例 2: 9 | 10 | 输入: 0 11 | 输出: false 12 | 示例 3: 13 | 14 | 输入: 9 15 | 输出: true 16 | 示例 4: 17 | 18 | 输入: 45 19 | 输出: false 20 | 进阶: 21 | 你能不使用循环或者递归来完成本题吗? 22 | */ 23 | 24 | /** 25 | * @param {number} n 26 | * @return {boolean} 27 | */ 28 | var isPowerOfThree = function (n) { 29 | if (n <= 0) { 30 | return false; 31 | } 32 | // 取巧做法, 用换底公式可得到: Math.log10(n) / Math.log10(3) = 等价于[此方法不存在只是说明问题] log3(n)。。。。 33 | var num = Math.log10(n) / Math.log10(3); 34 | return num % 1 === 0; 35 | }; 36 | 37 | const re = isPowerOfThree(81); 38 | 39 | console.log(re); 40 | 41 | 42 | 43 | 44 | /** 45 | * leecode 耗时最少解法 46 | * @param {number} n 47 | * @return {boolean} 48 | */ 49 | var isPowerOfThree = function (n) { 50 | let a = n; 51 | while (a !== 0) { 52 | if (a === 1) { 53 | return true; 54 | } 55 | if (a % 3 !== 0) { 56 | return false; 57 | } 58 | a = Math.floor(a / 3); 59 | } 60 | return false; 61 | }; 62 | -------------------------------------------------------------------------------- /algorithm/leecode/lee35.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个排序数组和一个目标值, 在数组中找到目标值, 并返回其索引。 如果目标值不存在于数组中, 返回它将会被按顺序插入的位置。 3 | * 4 | * 你可以假设数组中无重复元素。 5 | * 6 | * 示例 1: 7 | * 输入: [1, 3, 5, 6], 5 8 | * 输出: 2 9 | * 示例 2: 10 | * 11 | * 输入: [1, 3, 5, 6], 2 12 | * 输出: 1 13 | * 示例 3: 14 | * 15 | * 输入: [1, 3, 5, 6], 7 16 | * 输出: 4 17 | * 示例 4: 18 | * 19 | * 输入: [1, 3, 5, 6], 0 20 | * 输出: 0 21 | */ 22 | 23 | function searchInsert(nums, target) { 24 | const len = nums.length 25 | if (target > nums[len - 1]) { 26 | return len 27 | } 28 | for (let index = 0; index < len; index++) { 29 | if (nums[index] >= target) { 30 | return index 31 | } else if (nums[index] < target && target < nums[index + 1]) { 32 | return index + 1; 33 | } 34 | } 35 | } 36 | 37 | console.log(searchInsert([1, 3, 5, 6], 7)) 38 | 39 | 40 | /** 41 | * leecode 耗时最少解法 42 | * @param {*} nums 43 | * @param {*} target 44 | */ 45 | var searchInsert1 = function (nums, target) { 46 | if (nums.includes(target)) { 47 | return nums.indexOf(target); 48 | } 49 | return nums.filter(el => el < target).length; 50 | }; 51 | -------------------------------------------------------------------------------- /algorithm/leecode/lee371.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 不用加减法计算两数只和 3 | */ 4 | 5 | function getSum(a, b) { 6 | if (b == 0 || a == 0) { //没有进为的时候完成运算 7 | return a || b; 8 | } 9 | let sum = a ^ b; // 进行异或计算 10 | let carry = (a & b) << 1; // 与计算并向左移一位 11 | return getSum(sum, carry); 12 | } 13 | 14 | const f = getSum(7, 10); 15 | 16 | console.log(f); 17 | 18 | 19 | /** 20 | * leecode 耗时最少解法 21 | * @param {number} a 22 | * @param {number} b 23 | * @return {number} 24 | */ 25 | var getSum = function (a, b) { 26 | if (a == 0) return b; 27 | if (b == 0) return a; 28 | var temp = a ^ b; 29 | var temp2 = (a & b) << 1; 30 | return getSum(temp, temp2); 31 | }; 32 | -------------------------------------------------------------------------------- /algorithm/leecode/lee389.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | 给定两个字符串 s 和 t, 它们只包含小写字母。 4 | 5 | 字符串 t 由字符串 s 随机重排, 然后在随机位置添加一个字母。 6 | 7 | 请找出在 t 中被添加的字母。 8 | 9 | 10 | 11 | 示例: 12 | 13 | 输入: 14 | s = "abcd" 15 | t = "acbde" 16 | 17 | 输出: 18 | e 19 | 20 | 解释: 21 | 'e' 22 | 是那个被添加的字母。 23 | */ 24 | 25 | 26 | /** 27 | * @param {string} s 28 | * @param {string} t 29 | * @return {character} 30 | * 31 | * 1 ^ 1 = 0 , 则将字母转化为数字,然后将最终的数组转换为字母, 同 lee136.js 32 | * 我的提交执行用时 33 | 已经战胜 95.31 % 的 javascript 提交记录 34 | */ 35 | var findTheDifference = function (s, t) { 36 | let sum = t[t.length - 1].charCodeAt(); 37 | for (let i = 0; i < s.length; i ++) { 38 | sum ^= (s[i].charCodeAt() ^ t[i].charCodeAt()); 39 | } 40 | 41 | return String.fromCharCode(sum); 42 | // 97 是小写字母 a 的 chatcode, 减去 97 之后加上10转36进制, 对应的方法就是 String.fromCharCode 43 | // return (sum - 97 + 10).toString(36); 44 | }; 45 | 46 | const s = "abcd"; 47 | const t = "abcde"; 48 | 49 | const re = findTheDifference(s, t); 50 | 51 | console.log(re); 52 | 53 | 54 | /** 55 | * leecode 耗时最少解法 56 | * @param {string} s 57 | * @param {string} t 58 | * @return {character} 59 | */ 60 | let findTheDifference = function (s, t) { 61 | let code = 0; 62 | for (let c of s + t) { 63 | code ^= c.charCodeAt(0); 64 | } 65 | return String.fromCharCode(code); 66 | }; 67 | 68 | /* 69 | let findTheDifference = function(s, t) { 70 | let map = new Map(); 71 | for (let c of s) { 72 | map.set(c, map.get(c) + 1 || 1); 73 | } 74 | for (let c of t) { 75 | let val = map.get(c); 76 | if (val === undefined || val === 0) { 77 | return c; 78 | } 79 | map.set(c, val - 1); 80 | } 81 | }; 82 | */ 83 | -------------------------------------------------------------------------------- /algorithm/leecode/lee461.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。 3 | 4 | 给出两个整数 x 和 y, 计算它们之间的汉明距离。 5 | 6 | 注意: 7 | 0≤ x, y < 231. 8 | 9 | 示例: 10 | 11 | 输入: x = 1, y = 4 12 | 13 | 输出: 2 14 | 15 | 解释: 16 | 1(0 0 0 1) 17 | 4(0 1 0 0)↑↑ 18 | 19 | 上面的箭头指出了对应二进制位不同的位置。 20 | */ 21 | 22 | /** 23 | * @param {number} x 24 | * @param {number} y 25 | * @return {number} 26 | * 异或运算符: 两个数转为二进制, 然后从高位开始比较, 如果相同则为0, 不相同则为1。 27 | */ 28 | var hammingDistance = function (x, y) { 29 | const re = (x ^ y); 30 | return re.toString(2).replace(0, '').length; 31 | }; 32 | 33 | 34 | /** 35 | * leecode 耗时最少解法 36 | * @param {number} x 37 | * @param {number} y 38 | * @return {number} 39 | * 40 | * 位运算经典案例 41 | * 42 | * 使用 ^ 异或获得两个数不同的二进制位。 43 | * 使用 z & 1 能够得到最后一位是不是 1 44 | * 使用 >>> 1 去掉最后一位 【 >>> 也可用于二进制转换】 45 | */ 46 | 47 | let hammingDistance = function (x, y) { 48 | let count = 0; 49 | let z = x ^ y; 50 | while (z) { 51 | if (z & 1) { 52 | count++; 53 | } 54 | z = z >>> 1; 55 | } 56 | return count; 57 | }; 58 | 59 | /** 60 | let hammingDistance = function(x, y) { 61 | let count = 0; 62 | while (x !== 0 || y !== 0) { 63 | if ((x & 1) !== (y & 1)) { 64 | count++; 65 | } 66 | x = x >>> 1; 67 | y = y >>> 1; 68 | } 69 | return count; 70 | }; 71 | */ 72 | -------------------------------------------------------------------------------- /algorithm/leecode/lee485.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个二进制数组, 计算其中最大连续1的个数。 3 | 4 | 示例 1: 5 | 6 | 输入: [1, 1, 0, 1, 1, 1] 7 | 输出: 3 8 | 解释: 开头的两位和最后的三位都是连续1, 所以最大连续1的个数是 3. 9 | 注意: 10 | 11 | 输入的数组只包含 0 和1。 12 | 输入数组的长度是正整数, 且不超过 10, 000。 13 | 14 | */ 15 | 16 | 17 | /** 18 | * @param {number[]} nums 19 | * @return {number} 20 | */ 21 | var findMaxConsecutiveOnes = function (nums) { 22 | let count = 0; 23 | let max = 0; 24 | for (let i = 0; i < nums.length; i ++) { 25 | count = nums[i] ? count + 1 : 0; 26 | max = max > count ? max : count; 27 | } 28 | return max; 29 | }; 30 | 31 | const re = findMaxConsecutiveOnes([1, 1, 0, 1, 1, 1]); 32 | 33 | console.log(re); 34 | 35 | 36 | /** 37 | * leecode 耗时最少解法 38 | * @param {number[]} nums 39 | * @return {number} 40 | */ 41 | let findMaxConsecutiveOnes = function (nums) { 42 | let max = 0; 43 | let count = 0; 44 | for (let i = 0; i < nums.length; ++i) { 45 | if (nums[i] !== 1 && count !== 0) { 46 | max = Math.max(max, count) 47 | count = 0; 48 | } else if (nums[i] === 1) { 49 | ++count; 50 | } 51 | } 52 | return Math.max(max, count); 53 | }; 54 | -------------------------------------------------------------------------------- /algorithm/leecode/lee560.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个整数数组和一个整数 k, 你需要找到该数组中和为 k 的连续的子数组的个数。 3 | 4 | 示例 1: 5 | 6 | 输入: nums = [1, 1, 1], k = 2 7 | 输出: 2, [1, 1] 与[1, 1] 为两种不同的情况。 8 | 说明: 9 | 10 | 数组的长度为[1, 20, 000]。 11 | 数组中元素的范围是[-1000, 1000], 且整数 k 的范围是[-1e7, 1e7]。 12 | */ 13 | 14 | /** 15 | * 先判断单个数, 如果等于则 reCount, 最慢 16 | */ 17 | let re = []; 18 | 19 | function subarraySum(nums, k) { 20 | let pos = 0; 21 | let index = 0; 22 | let reCount = 0; 23 | let sum = 0; 24 | while (pos < nums.length) { 25 | sum += nums[index]; 26 | if(sum === k) { 27 | reCount++; 28 | re.push(nums.slice(pos, index + 1)); 29 | } 30 | if (++index >= nums.length) { 31 | index = ++ pos + 1; 32 | sum = nums[pos]; 33 | 34 | if (sum === k) { 35 | reCount++; 36 | re.push(nums.slice(pos, pos + 1)); 37 | } 38 | } 39 | } 40 | 41 | return reCount; 42 | } 43 | 44 | /** 45 | * 先判断当前数字, 等于则 res 自增, 然后和其后的数逐个求和, 遇到等于 k 的情况则 res 自增 46 | * @param {*} nums 47 | * @param {*} k 48 | */ 49 | function subarraySum1(nums, k) { 50 | let sums = 0; 51 | let res = 0; 52 | for (let index = 0; index < nums.length; index++) { 53 | sums = nums[index]; 54 | if(sums === k) { 55 | res ++; 56 | } 57 | 58 | for (var j = index + 1; j < nums.length; j++) { 59 | sums += nums[j]; 60 | if (sums == k) ++res; 61 | } 62 | } 63 | 64 | return res; 65 | } 66 | 67 | 68 | function subarraySum2(nums, k) { 69 | var res = 0; 70 | var sum = 0; 71 | 72 | var map = new Map(); 73 | map.set(0, 1); 74 | for (var i = 0; i < nums.length; i++) { 75 | sum += nums[i]; 76 | 77 | if (map.get(sum - k)) { 78 | res += map.get(sum - k); 79 | } 80 | if (map.get(sum)) { 81 | map.set(sum, map.get(sum) + 1); 82 | } else { 83 | map.set(sum, 1); 84 | } 85 | } 86 | 87 | return res; 88 | } 89 | 90 | const subArrCount = subarraySum([2, 1, 1, 1, 2, -1, 1, 1], 2); 91 | const subArrCount1 = subarraySum1([2, 1, 1, 1, 2, -1, 1, 1], 2); 92 | const subArrCount2 = subarraySum2([2, 1, 1, 1, 2, -1, 1, 1], 2); 93 | console.log(subArrCount, subArrCount1, subArrCount2); 94 | console.log(re); 95 | 96 | 97 | /** 98 | * leecode 耗时最少解法 99 | * @param {number[]} nums 100 | * @param {number} k 101 | * @return {number} 102 | */ 103 | var subarraySum = function (nums, k) { 104 | let res = 0, 105 | sum = 0, 106 | n = nums.length; 107 | let m = new Map(); 108 | m.set(0, 1); 109 | for (let i = 0; i < n; i++) { 110 | sum += nums[i]; 111 | res += m.has(sum - k) ? m.get(sum - k) : 0; 112 | let cur_sum = m.has(sum) ? m.get(sum) : 0; 113 | m.set(sum, cur_sum + 1); 114 | } 115 | return res; 116 | }; 117 | -------------------------------------------------------------------------------- /algorithm/leecode/lee605.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 假设你有一个很长的花坛, 一部分地块种植了花, 另一部分却没有。 可是, 花卉不能种植在相邻的地块上, 它们会争夺水源, 两者都会死去。 3 | 4 | 给定一个花坛( 表示为一个数组包含0和1, 其中0表示没种植花, 1 表示种植了花), 和一个数 n。 能否在不打破种植规则的情况下种入 n 朵花? 能则返回True, 不能则返回False。 5 | 6 | 示例 1: 7 | 8 | 输入: flowerbed = [1, 0, 0, 0, 1], n = 1 9 | 输出: True 10 | 示例 2: 11 | 12 | 输入: flowerbed = [1, 0, 0, 0, 1], n = 2 13 | 输出: False 14 | 注意: 15 | 16 | 数组内已种好的花不会违反种植规则。 17 | 输入的数组长度范围为[1, 20000]。 18 | n 是非负整数, 且不会超过输入数组的大小。 19 | */ 20 | 21 | /** 22 | * @param {number[]} flowerbed 23 | * @param {number} n 24 | * @return {boolean} 25 | * 26 | * 我的提交执行用时 27 | 已经战胜 87.18 % 的 javascript 提交记录 28 | */ 29 | var canPlaceFlowers = function (flowerbed, n) { 30 | for (let i = 0; i < flowerbed.length; i++) { 31 | // 因为数组里有大量 0 , 所以经常执行这个 逻辑或。 32 | const pre = flowerbed[i - 1] || 0; 33 | const next = flowerbed[i + 1] || 0; 34 | 35 | console.log(pre, flowerbed[i], next); 36 | 37 | // 当前数和前后数只和为 0 则可以种植 38 | n -= (pre + flowerbed[i] + next) ? 0 : (flowerbed[i] = 1, n++, 1); 39 | if (n <= 0) { 40 | return true; 41 | } 42 | } 43 | return false; 44 | }; 45 | 46 | const re = canPlaceFlowers([1, 0, 0, 0, 1], 2); 47 | console.log(re); 48 | 49 | 50 | 51 | /** 52 | * leecode 耗时最少解法 53 | * @param {number[]} flowerbed 54 | * @param {number} n 55 | * @return {boolean} 56 | */ 57 | var canPlaceFlowers = function (flowerbed, n) { 58 | var count = 0 59 | for (var i = 0; i < flowerbed.length; i++) { 60 | if (flowerbed[i] == 0) { 61 | if (i == 0 && flowerbed[i + 1] != 1) { 62 | flowerbed[i] = 1 63 | count++ 64 | } else if (i == flowerbed.length - 1 && flowerbed[i - 1] != 1) { 65 | flowerbed[i] = 1 66 | count++ 67 | } else { 68 | if (flowerbed[i - 1] != 1 && flowerbed[i + 1] != 1) { 69 | flowerbed[i] = 1 70 | count++ 71 | } 72 | } 73 | } 74 | } 75 | if (count < n) { 76 | return false 77 | } else { 78 | return true 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /algorithm/leecode/lee657.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 在二维平面上, 有一个机器人从原点(0, 0) 开始。 给出它的移动顺序, 判断这个机器人在完成移动后是否在(0, 0) 处结束。 3 | 4 | 移动顺序由字符串表示。 字符 move[i] 表示其第 i 次移动。 机器人的有效动作有 R( 右), L( 左), U( 上) 和 D( 下)。 如果机器人在完成所有动作后返回原点, 则返回 true。 否则, 返回 false。 5 | 6 | 注意: 机器人“ 面朝” 的方向无关紧要。“ R” 将始终使机器人向右移动一次,“ L” 将始终向左移动等。 此外, 假设每次移动机器人的移动幅度相同。 7 | 8 | 输入: "UD" 9 | 输出: true 10 | 解释: 机器人向上移动一次, 然后向下移动一次。 所有动作都具有相同的幅度, 因此它最终回到它开始的原点。 因此, 我们返回 true。 11 | 12 | 输入: "LL" 13 | 输出: false 14 | 解释: 机器人向左移动两次。 它最终位于原点的左侧, 距原点有两次“ 移动” 的距离。 我们返回 false, 因为它在移动结束时没有返回原点。 15 | */ 16 | 17 | /** 18 | * @param {string} moves 19 | * @return {boolean} 20 | * 思路: 相反方向的移动个数一样,则一定能回到原点。 21 | * 1. 移动路径为奇数, 不可能回到原点 22 | * 2. u.count === d.count && l.count === r.count 一定可以回到原点 23 | * 24 | * 我的提交执行用时 25 | * 已经战胜 92.40 % 的 javascript 提交记录 26 | * 27 | * 此方法是非迭代方法, 但是问题也很明显,不稳定,可以回到原点的情况下, 会执行四次 match 。 28 | */ 29 | var judgeCircle = function (moves) { 30 | if (moves.length % 2 !== 0) { 31 | return false; 32 | } 33 | 34 | // 我利用正则获取字符串中某个字符的长度,但是 match 可能会返回 null, 则需要先 test 35 | // 做容错, 未解决这个问题, 我每个字符串加一个无效移动【等价抵消】: UPLR 来避免 match 返回 null 36 | moves += 'UDLR'; 37 | 38 | const uCount = moves.match(/U/g).length; 39 | const dCount = moves.match(/D/g).length; 40 | if (uCount !== dCount) { 41 | return false; 42 | } 43 | 44 | const lCount = moves.match(/L/g).length; 45 | const rCount = moves.match(/R/g).length; 46 | if (lCount !== rCount) { 47 | return false; 48 | } 49 | 50 | return true; 51 | }; 52 | 53 | 54 | const re = judgeCircle('LRUDLLRD'); 55 | console.log(re); 56 | 57 | 58 | 59 | /** 60 | * leecode 耗时最少解法 61 | * @param {string} moves 62 | * @return {boolean} 63 | */ 64 | var judgeCircle = function(moves) { 65 | let x = 0; 66 | let y = 0; 67 | 68 | let actions = moves.split(''); 69 | actions.forEach((act) => { 70 | switch(act) { 71 | case 'U': { 72 | y++; 73 | break; 74 | } 75 | case 'D': { 76 | y--; 77 | break; 78 | } 79 | case 'R': { 80 | x++; 81 | break; 82 | } 83 | case 'L': { 84 | x--; 85 | break; 86 | } 87 | } 88 | }) 89 | 90 | return x == 0 && y == 0; 91 | }; 92 | -------------------------------------------------------------------------------- /algorithm/leecode/lee7.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 3 | * 4 | * 123 -> 321 5 | * -12300 -> -321 6 | */ 7 | 8 | function reverse(x) { 9 | var res = 0; 10 | var symbol = x > 0; 11 | x = x > 0 ? x : -x 12 | while (x != 0) { 13 | // 拿到最后一位拼到新数字的后面 14 | res = res * 10 + Math.floor(x) % 10; 15 | x = Math.floor(x / 10) 16 | } 17 | if (res > Math.pow(2, 31) - 1) return 0; 18 | return symbol ? res : -res; 19 | } 20 | 21 | console.log(reverse(1534269)); 22 | 23 | 24 | /** 25 | * leecode 耗时最少解法 26 | * @param {number} x 27 | * @return {number} 28 | */ 29 | let reverse = function (x) { 30 | let res = 0; 31 | while (x !== 0) { 32 | res = res * 10 + x % 10; 33 | x = x < 0 ? Math.ceil(x / 10) : Math.floor(x / 10); 34 | } 35 | return res < -(2 ** 31) || res > 2 ** 31 - 1 ? 0 : res; 36 | }; 37 | -------------------------------------------------------------------------------- /algorithm/leecode/lee709.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 实现函数 ToLowerCase(), 该函数接收一个字符串参数 str, 并将该字符串中的大写字母转换成小写字母, 之后返回新的字符串。 3 | * 4 | * 输入: "Hello" 5 | * 输出: "hello" 6 | */ 7 | 8 | /** 9 | * @param {string} str 10 | * @return {string} 11 | * 我的提交执行用时 12 | * 已经战胜 81.64 % 的 javascript 提交记录 13 | */ 14 | var toLowerCase = function (str) { 15 | const letterMap = { 16 | A: 'a', 17 | B: 'b', 18 | C: 'c', 19 | D: 'd', 20 | E: 'e', 21 | F: 'f', 22 | G: 'g', 23 | H: 'h', 24 | I: 'i', 25 | J: 'j', 26 | K: 'k', 27 | L: 'l', 28 | M: 'm', 29 | N: 'n', 30 | O: 'o', 31 | P: 'p', 32 | Q: 'q', 33 | R: 'r', 34 | S: 's', 35 | T: 't', 36 | U: 'u', 37 | V: 'v', 38 | W: 'w', 39 | X: 'x', 40 | Y: 'y', 41 | Z: 'z', 42 | }; 43 | 44 | let lowerCaseLetter = ''; 45 | for (let index = 0; index < str.length; index ++) { 46 | const curLetter = str[index]; 47 | lowerCaseLetter += letterMap[curLetter] || curLetter; 48 | } 49 | 50 | return lowerCaseLetter; 51 | }; 52 | 53 | const re = toLowerCase('AbCdEfG'); 54 | 55 | console.log(re); 56 | 57 | 58 | 59 | /** 60 | * leecode 耗时最少解法 61 | * @param {string} str 62 | * @return {string} 63 | */ 64 | let toLowerCase = function (str) { 65 | let letterDictionary = { 66 | A: "a", 67 | B: "b", 68 | C: "c", 69 | D: "d", 70 | E: "e", 71 | F: "f", 72 | G: "g", 73 | H: "h", 74 | I: "i", 75 | J: "j", 76 | K: "k", 77 | L: "l", 78 | M: "m", 79 | N: "n", 80 | O: "o", 81 | P: "p", 82 | Q: "q", 83 | R: "r", 84 | S: "s", 85 | T: "t", 86 | U: "u", 87 | V: "v", 88 | W: "w", 89 | X: "x", 90 | Y: "y", 91 | Z: "z" 92 | }; 93 | let result = ""; 94 | for (let i = 0, len = str.length; i < len; i += 1) { 95 | result += str[i] in letterDictionary ? letterDictionary[str[i]] : str[i]; 96 | } 97 | return result; 98 | }; 99 | 100 | 101 | /** 102 | * @param {string} str 103 | * @return {string} 104 | * other 105 | */ 106 | var toLowerCase = function (str) { 107 | if (str.length === 0) { 108 | return '' 109 | } 110 | let newStr = '' 111 | for (let i = 0; i < str.length; i++) { 112 | let code = str[i].charCodeAt() 113 | // 判断是否ASCII码区间是否为大写字母区间 114 | if (code >= 65 && code <= 90) { 115 | code += 32 116 | newStr += String.fromCharCode(code) 117 | } else { 118 | newStr += str[i] 119 | } 120 | } 121 | return newStr 122 | }; 123 | -------------------------------------------------------------------------------- /algorithm/leecode/lee728.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 自除数 是指可以被它包含的每一位数除尽的数。 3 | 4 | 例如, 128 是一个自除数, 因为 128 % 1 == 0, 128 % 2 == 0, 128 % 8 == 0。 5 | 6 | 还有, 自除数不允许包含 0。 7 | 8 | 给定上边界和下边界数字, 输出一个列表, 列表的元素是边界( 含边界) 内所有的自除数。 9 | 10 | 示例 1: 11 | 12 | 输入: 13 | 上边界left = 1, 下边界right = 22 14 | 输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22] 15 | 注意: 16 | 17 | 每个输入参数的边界满足 1 <= left <= right <= 10000。 18 | */ 19 | 20 | 21 | /** 22 | * @param {number} left 23 | * @param {number} right 24 | * @return {number[]} 25 | */ 26 | var selfDividingNumbers = function (left, right) { 27 | const selfDividingList = []; 28 | for (let i = left; i <= right; i ++) { 29 | let iStr = i.toString(); 30 | let succ = true; 31 | for (let j = 0; j < iStr.length; j++) { 32 | if (!+iStr[j] || (i % iStr[j]) !== 0) { 33 | succ = false; 34 | break; 35 | } 36 | // console.log(iStr, iStr[j], (i % iStr[j]), !+iStr[j], (i % iStr[j]) !== 0); 37 | } 38 | succ && selfDividingList.push(i); 39 | } 40 | 41 | return selfDividingList 42 | }; 43 | 44 | 45 | const re = selfDividingNumbers(9, 22); 46 | 47 | console.log(re); 48 | 49 | 50 | 51 | /** 52 | * leecode 耗时最少解法 53 | * @param {number} left 54 | * @param {number} right 55 | * @return {number[]} 56 | */ 57 | let selfDividingNumbers = function (left, right) { 58 | let res = []; 59 | for (let i = left; i <= right; ++i) { 60 | if (helper(i)) { 61 | res.push(i); 62 | } 63 | } 64 | return res; 65 | }; 66 | 67 | let helper = function (num) { 68 | let tag = num; 69 | while (num > 0) { 70 | // 核心逻辑, 注: 10 % 0 不会抛错, 返回 NaN 71 | if (tag % (num % 10) !== 0) { 72 | return false; 73 | } 74 | // 霸气取整 75 | num = ~~(num / 10); 76 | } 77 | return true; 78 | }; 79 | -------------------------------------------------------------------------------- /algorithm/leecode/lee771.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定字符串J 代表石头中宝石的类型, 和字符串 S代表你拥有的石头。 S 中每个字符代表了一种你拥有的石头的类型, 3 | * 你想知道你拥有的石头中有多少是宝石。J 中的字母不重复, J 和 S中的所有字符都是字母。 字母区分大小写, 因此 "a" 4 | * 和 "A" 是不同类型的石头。 5 | */ 6 | 7 | /** 8 | 示例 1: 9 | 10 | 输入: J = "aA", S = "aAAbbbb" 11 | 输出: 3 12 | 示例 2: 13 | 14 | 输入: J = "z", S = "ZZ" 15 | 输出: 0 16 | */ 17 | 18 | var numJewelsInStones = function (J, S) { 19 | const sList = S.split(''); 20 | let count = 0; 21 | sList.map((item) => { 22 | if (J.indexOf(item) !== -1) { 23 | count ++; 24 | } 25 | }); 26 | 27 | return count; 28 | }; 29 | 30 | 31 | const count = numJewelsInStones('abc', 'AAaaBbCc'); 32 | 33 | console.log(count); 34 | 35 | 36 | /** 37 | * leecode 耗时最少解法 38 | * @param {string} J 39 | * @param {string} S 40 | * @return {number} 41 | */ 42 | var numJewelsInStones = function (J, S) { 43 | var num = 0 44 | 45 | for (var i = 0; i < J.length; i++) { 46 | for (var j = 0; j < S.length; j++) { 47 | if (J[i] === S[j]) { 48 | num++ 49 | } 50 | } 51 | } 52 | 53 | return num 54 | }; 55 | -------------------------------------------------------------------------------- /algorithm/leecode/lee896.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 如果数组是单调递增或单调递减的, 那么它是单调的。 3 | 4 | 如果对于所有 i <= j, A[i] <= A[j], 那么数组 A 是单调递增的。 如果对于所有 i <= j, A[i] > = A[j], 那么数组 A 是单调递减的。 5 | 6 | 当给定的数组 A 是单调数组时返回 true, 否则返回 false。 7 | 8 | 9 | 10 | 示例 1: 11 | 12 | 输入:[1, 2, 2, 3] 13 | 输出: true 14 | 示例 2: 15 | 16 | 输入:[6, 5, 4, 4] 17 | 输出: true 18 | 示例 3: 19 | 20 | 输入:[1, 3, 2] 21 | 输出: false 22 | 示例 4: 23 | 24 | 输入:[1, 2, 4, 5] 25 | 输出: true 26 | 示例 5: 27 | 28 | 输入:[1, 1, 1] 29 | 输出: true 30 | 31 | 32 | 提示: 33 | 34 | 1 <= A.length <= 50000 - 35 | 100000 <= A[i] <= 100000 36 | */ 37 | 38 | 39 | /** 40 | * @param {number[]} A 41 | * @return {boolean} 42 | * 43 | * 从前往后迭代, 两个相邻的数之差,第一次不相等的时候,把他录到 difference 上 作为基准,这个数和之后任意两个数 44 | * 的差求乘, 如果和为整数 则必定是相同的升降序。 45 | */ 46 | var isMonotonic = function (A) { 47 | if (A.length < 3) { 48 | return true; 49 | } 50 | 51 | let difference = 0; 52 | for(let i = 0; i < A.length - 1; i ++) { 53 | const di = A[i] - A[i + 1]; 54 | if (difference === 0) { 55 | difference = di; 56 | } else if (di * difference < 0) { 57 | return false; 58 | } 59 | } 60 | return true; 61 | }; 62 | 63 | const re = isMonotonic([1, 2, 5, 4, 5]); 64 | console.log(re); 65 | 66 | 67 | 68 | /** 69 | * leecode 耗时最少解法 70 | * @param {number[]} A 71 | * @return {boolean} 72 | * 73 | * 没想明白为啥比我的快 74 | */ 75 | var isMonotonic = function (A) { 76 | let x = 0; 77 | 78 | for (let i = 0; i < A.length - 1; i += 1) { 79 | if (A[i] > A[i + 1]) { 80 | x = 1; 81 | break; 82 | } else if (A[i] < A[i + 1]) { 83 | x = -1; 84 | break; 85 | } 86 | } 87 | let result = true; 88 | if (x === -1) { 89 | for (let i = 0; i < A.length - 1; i += 1) { 90 | if (A[i] > A[i + 1]) { 91 | result = false; 92 | } 93 | } 94 | } else if (x === 1) { 95 | for (let i = 0; i < A.length - 1; i += 1) { 96 | if (A[i] < A[i + 1]) { 97 | result = false; 98 | } 99 | } 100 | } 101 | return result 102 | }; 103 | -------------------------------------------------------------------------------- /algorithm/leecode/lee9.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 回文数 3 | * 121 -> true 4 | * -11 -> false 5 | * 10 -> false 6 | * 7 | * 翻转数组来比较. 8 | * 其实比较第一位和最后一位也可以. 不相等则返回 false 9 | */ 10 | 11 | function isPalindrome(x) { 12 | if (x < 0) { 13 | return false 14 | } 15 | 16 | let rex = 0 17 | let tx = x; 18 | while(tx != 0) { 19 | rex = rex * 10 + Math.floor(tx) % 10 20 | tx = Math.floor(tx / 10) 21 | } 22 | 23 | return rex === x 24 | } 25 | 26 | console.log(isPalindrome(21212)) 27 | 28 | 29 | /** 30 | * leecode 耗时最少解法 31 | * @param {number} x 32 | * @return {boolean} 33 | */ 34 | let isPalindrome = function (x) { 35 | if (x < 0 || (x % 10 === 0 && x !== 0)) return false; 36 | let revert = 0; 37 | while (x > revert) { 38 | revert = (revert * 10) + x % 10; 39 | x = Math.floor(x / 10); 40 | } 41 | return x === revert || x === Math.floor(revert / 10); 42 | }; 43 | -------------------------------------------------------------------------------- /algorithm/leecode/lee905.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给定一个非负整数数组 A, 返回一个由 A 的所有偶数元素组成的数组, 后面跟 A 的所有奇数元素。 3 | * 你可以返回满足此条件的任何数组作为答案。 4 | * 5 | * 输入:[3, 1, 2, 4] 6 | 输出:[2, 4, 3, 1] 7 | 输出[4, 2, 3, 1],[2, 4, 1, 3] 和[4, 2, 1, 3] 也会被接受。 8 | */ 9 | 10 | 11 | /** 12 | * @param {number[]} A 13 | * @return {number[]} 14 | */ 15 | var sortArrayByParity = function (A) { 16 | let i = 0; 17 | 18 | const f1 = [], 19 | f2 = []; 20 | while (i < A.length) { 21 | if (A[i] % 2 === 0) { 22 | f1.push(A[i]); 23 | } else { 24 | f2.push(A[i]); 25 | } 26 | i++; 27 | } 28 | 29 | return [...f1, ...f2]; 30 | }; 31 | 32 | 33 | const re = sortArrayByParity([1, 2, 4, 7, 3, 8, 9]); 34 | 35 | console.log(re); 36 | 37 | 38 | /** 39 | * leecode 耗时最少解法 40 | * @param {number[]} A 41 | * @return {number[]} 42 | */ 43 | var sortArrayByParity = function (A) { 44 | let evenList = []; 45 | let oddList = []; 46 | 47 | A.forEach((num) => { 48 | if (num % 2 == 0) { 49 | oddList.push(num); 50 | } else { 51 | evenList.push(num); 52 | } 53 | }) 54 | 55 | return oddList.concat(evenList); 56 | }; 57 | -------------------------------------------------------------------------------- /algorithm/leecode/lee929.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 每封电子邮件都由一个本地名称和一个域名组成, 以 @ 符号分隔。 3 | 4 | 例如, 在 alice @leetcode.com中, alice 是本地名称, 而 leetcode.com 是域名。 5 | 6 | 除了小写字母, 这些电子邮件还可能包含 ',' 7 | 或 '+'。 8 | 9 | 如果在电子邮件地址的本地名称部分中的某些字符之间添加句点( '.'), 10 | 则发往那里的邮件将会转发到本地名称中没有点的同一地址。 例如, "alice.z@leetcode.com” 和 “alicez@leetcode.com” 会转发到同一电子邮件地址。 (请注意,此规则不适用于域名。) 11 | 12 | 如果在本地名称中添加加号( '+'), 13 | 则会忽略第一个加号后面的所有内容。 这允许过滤某些电子邮件, 例如 m.y + name @email.com 将转发到 my @email.com。( 同样, 此规则不适用于域名。) 14 | 15 | 可以同时使用这两个规则。 16 | 17 | 给定电子邮件列表 emails, 我们会向列表中的每个地址发送一封电子邮件。 实际收到邮件的不同地址有多少? 18 | 19 | 输入:["test.email+alex@leetcode.com", "test.e.mail+bob.cathy@leetcode.com", "testemail+david@lee.tcode.com"] 20 | 输出: 2 21 | 解释: 实际收到邮件的是 "testemail@leetcode.com" 22 | 和 "testemail@lee.tcode.com"。 23 | 24 | */ 25 | 26 | 27 | /** 28 | * @param {string[]} emails 29 | * @return {number} 30 | * 31 | * 我的提交执行用时 32 | * 已经战胜 92.13 % 的 javascript 提交记录 33 | */ 34 | var numUniqueEmails = function (emails) { 35 | for (let i = 0; i < emails.length; i ++) { 36 | const emailItem = emails[i]; 37 | const emailSplit = emailItem.split('@'); 38 | emails[i] = emailSplit[0].replace(/\+.*/g, '').replace(/\./g, '') + emailSplit[1]; 39 | } 40 | 41 | return new Set(emails).size; 42 | }; 43 | 44 | const emailList = ["test.email+alex@leetcode.com", "test.e.mail+bob.cathy@leetcode.com", "testemail+david@lee.tcode.com"]; 45 | const size = numUniqueEmails(emailList); 46 | 47 | console.log(size); 48 | 49 | 50 | /** 51 | * leecode 耗时最少解法 52 | * @param {string[]} emails 53 | * @return {number} 54 | */ 55 | var numUniqueEmails = function (emails) { 56 | const obj = {}; 57 | let result = 0; 58 | for (let i = 0; i < emails.length; i++) { 59 | const items = emails[i].split('@'); 60 | let index = 0; 61 | const domain = items[1]; 62 | const address = items[0].replace(/(\+(\w|\W)+|\.)/g, ''); 63 | const hash = domain + address; 64 | if (!obj[hash]) { 65 | result += 1; 66 | obj[hash] = 1; 67 | } 68 | } 69 | return result; 70 | }; 71 | -------------------------------------------------------------------------------- /algorithm/leecode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leecode", 3 | "version": "1.0.0", 4 | "description": "> 共计 ${data.t1} 题【已实现】", 5 | "main": "lee1.js", 6 | "scripts": { 7 | "build": "node ./shell.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "string-template": "^1.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /algorithm/leecode/readme.md: -------------------------------------------------------------------------------- 1 | # Leecode 2 | 3 | > 共计 32 题【已实现】 4 | 5 | | | | | | | | 6 | | ------ | ------ | ------ | ------ | ------ | ------ | 7 | | [lee1.js](./lee1.js) | [lee2.js](./lee2.js) | [lee7.js](./lee7.js) | [lee9.js](./lee9.js) | [lee14.js](./lee14.js) | [lee27.js](./lee27.js) | 8 | | [lee28.js](./lee28.js) | [lee35.js](./lee35.js) | [lee118.js](./lee118.js) | [lee119.js](./lee119.js) | [lee136.js](./lee136.js) | [lee169.js](./lee169.js) | 9 | | [lee189.js](./lee189.js) | [lee190.js](./lee190.js) | [lee191.js](./lee191.js) | [lee231.js](./lee231.js) | [lee258.js](./lee258.js) | [lee268.js](./lee268.js) | 10 | | [lee326.js](./lee326.js) | [lee371.js](./lee371.js) | [lee389.js](./lee389.js) | [lee461.js](./lee461.js) | [lee485.js](./lee485.js) | [lee560.js](./lee560.js) | 11 | | [lee605.js](./lee605.js) | [lee657.js](./lee657.js) | [lee709.js](./lee709.js) | [lee728.js](./lee728.js) | [lee771.js](./lee771.js) | [lee896.js](./lee896.js) | 12 | | [lee905.js](./lee905.js) | [lee929.js](./lee929.js) 13 | -------------------------------------------------------------------------------- /algorithm/leecode/shell.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const stringTemplate = require('string-template'); 4 | 5 | /** 6 | * 7 | * @param {*} fn: SPS : (a, b, c, ..., cb) => {} 8 | */ 9 | function promiseIfyCps(fn) { 10 | return (...args) => { 11 | return new Promise((resolve, reject) => { 12 | fn(...args, (error, data) => { 13 | if (error) { 14 | reject(error); 15 | } 16 | 17 | resolve(data); 18 | }); 19 | }) 20 | }; 21 | } 22 | 23 | ['readdir', 'readFile', 'stat', 'write', 'writeFile'].map((item, index) => { 24 | fs[item + 'Promise'] = promiseIfyCps(fs[item]); 25 | }); 26 | 27 | 28 | const filterList = [/^lee*/]; 29 | const ignoreList = [/\.todo\./]; 30 | const numReg = /\d+/; 31 | const sortFn = (a, b) => { 32 | try { 33 | return a.match(numReg)[0] - b.match(numReg)[0]; 34 | } catch(err) { 35 | return true; 36 | } 37 | } 38 | 39 | 40 | function filter (list = []) { 41 | return list.filter((li) => { 42 | const filterMap = filterList.filter((fi) => fi.test(li)); 43 | const ignoreMap = ignoreList.filter((fi) => !fi.test(li)); 44 | 45 | return filterMap.length === filterList.length && ignoreMap.length === ignoreList.length; 46 | }).sort(sortFn); 47 | } 48 | 49 | const BASE_PATH = './'; 50 | const ROOT_PATH = './algorithm/leecode/'; 51 | const OUT_FILE = path.resolve('./readme.md'); 52 | const DEFAULT_CONTEXT = [ 53 | '# Leecode\n\n', 54 | '> 共计 {count} 题【已实现】\n\n' 55 | ]; 56 | 57 | const ROOT_TABLE_DESC = '\n\n'; 58 | const DEFAULT_TABLE_length = 6; 59 | const DEFAULT_TABLE = [ 60 | '| | | | | | |\n', 61 | '| ------ | ------ | ------ | ------ | ------ | ------ |\n', 62 | ]; 63 | 64 | async function genReadmeMd () { 65 | const fileList = await fs.readdirPromise(path.resolve(BASE_PATH)); 66 | const filterList = filter(fileList); 67 | 68 | const baseList = []; 69 | const rootList = []; 70 | 71 | filterList.forEach((item, index) => { 72 | let baseRow = `| [${item}](${BASE_PATH}${item}) `; 73 | let rootRow = `| [${item}](${ROOT_PATH}${item}) `; 74 | if ((index + 1) % DEFAULT_TABLE_length === 0) { 75 | baseRow = baseRow + '|\n'; 76 | rootRow = rootRow + '|\n'; 77 | } 78 | baseList.push(baseRow); 79 | rootList.push(rootRow); 80 | }); 81 | 82 | baseList.unshift(...DEFAULT_CONTEXT.map((item) => stringTemplate(item, { 83 | count: baseList.length 84 | })) , ...DEFAULT_TABLE); 85 | rootList.unshift(...DEFAULT_TABLE); 86 | const allList = baseList.concat(ROOT_TABLE_DESC, rootList); 87 | 88 | await fs.writeFilePromise(OUT_FILE, allList.join('')); 89 | 90 | return [fileList, filterList]; 91 | } 92 | 93 | 94 | genReadmeMd().then(([fileList, { length }]) => { 95 | console.log('自动输出完成'); 96 | console.log(`已完成:${length}, other:${fileList.length - length}.`); 97 | }) 98 | -------------------------------------------------------------------------------- /algorithm/leecode/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | string-template@^1.0.0: 6 | version "1.0.0" 7 | resolved "http://registry.npm.taobao.org/string-template/download/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" 8 | -------------------------------------------------------------------------------- /design/pattern/readme.md: -------------------------------------------------------------------------------- 1 | # 设计模式 2 | 3 | 设计模式(Design pattern)代表了最佳的实践 4 | 5 | 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 6 | 7 | 8 | ## Typescript 9 | 10 | 很多模式依赖约束,接口,继承,多态 等等特性,所以单出的 js 写出的设计模式往往很别扭。生搬硬套,没有意义。TS 则不同,有很好的土壤。 11 | 12 | 13 | ## 设计模式六大原则 14 | 15 | ### 总原则:开闭原则(Open Close Principle) 16 | 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。 17 | 18 | 1. 单一职责原则 19 | 不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。 20 | 21 | 2. 里氏替换原则(Liskov Substitution Principle) 22 | 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。 23 | 24 | 里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。 25 | 26 | 3. 依赖倒转原则(Dependence Inversion Principle) 27 | 这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。 28 | 29 | 4. 接口隔离原则(Interface Segregation Principle) 30 | 这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。 31 | 32 | 5. 迪米特法则(最少知道原则)(Demeter Principle) 33 | 就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。 34 | 35 | 最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。 36 | 37 | 6. 合成复用原则(Composite Reuse Principle) 38 | 原则是尽量首先使用合成/聚合的方式,而不是使用继承。 39 | 40 | 41 | ## 23种设计模式 42 | 43 | ### 创建模式 44 | 45 | 1. [单例模式: Singleton](./singleton/readme.md) 46 | 2. [工厂模式: Factory](./factory/readme.md) 47 | 48 | 49 | ### 参考· 50 | 51 | - https://zhuanlan.zhihu.com/p/43283016 52 | - https://www.cnblogs.com/hegx/p/6094604.html 53 | - https://www.cnblogs.com/geek6/p/3951677.html 54 | -------------------------------------------------------------------------------- /design/pattern/singleton/readme.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | 3 | > 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用 4 | 5 | 6 | ### 基本条件 7 | 8 | 1. 私有构造 9 | 2. 私有静态属性引用实例 10 | 3. 静态方法提供实例 11 | 12 | ### 特征 13 | 14 | 1. 单例模式类只能有一个实例 15 | 2. 单例模式类必须自己创建自己的唯一实例 16 | 3. 单例模式类必须给所有其他对象提供这一实例 17 | 18 | 19 | ### 代码实现 20 | 21 | 完整代码参考: [singleton](./singleton.ts) 22 | 23 | #### 懒汉式 24 | 25 | 由于 js 不存在多线程,也没有异步的构造,所以 js 的懒汉反而不需要什么同步机制啊,锁机制之类的控制 26 | 27 | ```typescript 28 | class Singleton { 29 | private static SingletonObj: Singleton = null; 30 | private constructor(...any: any[]) { 31 | Object.assign(this, ...any); 32 | } 33 | 34 | static getInstance(...any: any[]): Singleton { 35 | // 在其他语言中这实际上有些线程不安全,但 js 是单线程语言则不存在这个问题。 36 | if (!this.SingletonObj) { 37 | // 用的时候创建 38 | // Lazy Loading, 如果从始至终从未使用过这个实例,则不会造成内存的浪费。 39 | this.SingletonObj = new Singleton(...any); 40 | } 41 | return this.SingletonObj; 42 | } 43 | } 44 | 45 | const sl: Singleton = Singleton.getInstance([1, 3, 5]); 46 | console.log(sl); 47 | ``` 48 | 49 | #### 饿汉式 50 | 51 | ```typescript 52 | class Singleton { 53 | private static SingletonObj: Singleton = new Singleton([1, 2, 4, 8]); 54 | private constructor(...any: any[]) { 55 | Object.assign(this, ...any); 56 | } 57 | 58 | static getInstance(): Singleton { 59 | return this.SingletonObj; 60 | } 61 | } 62 | 63 | // error: 类“Singleton”的构造函数是私有的,仅可在类声明中访问。 64 | // const sl: Singleton = new Singleton(1, 3, 5); 65 | 66 | const sl: Singleton = Singleton.getInstance(); 67 | console.log(sl); 68 | ``` 69 | 70 | 71 | ### 注意 72 | 73 | - 单例模式是可以达到节省资源的目的,但如果为了节省资源就使用单例模式的话可能造成单例模式的滥用。单例模式是为了确保在整个应用期间只有一个实例,以达到用户的特定的使用目的。 74 | - 多线程环境需要考虑锁机制 75 | - 实例指针一定要设为静态, 因为 getInstance 是静态的 76 | - 懒汉是 时间换空间, 恶汉是空间换时间 77 | 78 | 79 | ### 应用、场景 80 | 81 | - 适合初始化复杂对象,大型对象,避免重复实例化造成多次开销。 82 | - 核心流程状态的一致性,比如交易之类的。 83 | - 依据场景,时间,空间等合理选择懒汉和恶汉。 84 | 85 | 86 | ### 弊端 87 | 88 | - 扩展困难,实例,构造都是 private。 89 | - 线程安全问题[多线程语言]。 90 | -------------------------------------------------------------------------------- /design/pattern/singleton/singleton.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 仅仅为了说明问题而使用中文做标识符,十分不提倡!!!! 3 | * 仅仅为了说明问题而使用中文做标识符,十分不提倡!!!! 4 | * 仅仅为了说明问题而使用中文做标识符,十分不提倡!!!! 5 | */ 6 | 7 | namespace 饿汉式 { 8 | class Singleton { 9 | private static SingletonObj: Singleton = new Singleton([1, 2, 4, 8]); 10 | private constructor(...any: any[]) { 11 | Object.assign(this, ...any); 12 | } 13 | 14 | static getInstance(): Singleton { 15 | return this.SingletonObj; 16 | } 17 | } 18 | 19 | // error: 类“Singleton”的构造函数是私有的,仅可在类声明中访问。 20 | // const sl: Singleton = new Singleton(1, 3, 5); 21 | 22 | const sl: Singleton = Singleton.getInstance(); 23 | 24 | console.log(sl); 25 | } 26 | 27 | namespace 懒汉式{ 28 | class Singleton { 29 | private static SingletonObj: Singleton = null; 30 | private constructor(...any: any[]) { 31 | Object.assign(this, ...any); 32 | } 33 | 34 | static getInstance(...any: any[]): Singleton { 35 | // 在其他语言中这实际上有些线程不安全,但 js 是单线程语言则不存在这个问题。 36 | if (!this.SingletonObj) { 37 | // 用的时候创建 38 | // Lazy Loading, 如果从始至终从未使用过这个实例,则不会造成内存的浪费。 39 | this.SingletonObj = new Singleton(...any); 40 | } 41 | 42 | return this.SingletonObj; 43 | } 44 | } 45 | 46 | // error: 类“Singleton”的构造函数是私有的,仅可在类声明中访问。 47 | // const sl: Singleton = new Singleton(1, 3, 5); 48 | 49 | const sl: Singleton = Singleton.getInstance([1, 3, 5]); 50 | 51 | console.log(sl); 52 | } 53 | -------------------------------------------------------------------------------- /dev.md: -------------------------------------------------------------------------------- 1 | # 注意 2 | 3 | 1. 如下两种命名方式是未完成 和 git 库, 不在提交范围之内 4 | 5 | - ._git_* 6 | - .TODO-* 7 | 8 | 9 | 2. 博客转载头 10 | 11 | - github 首页(star+watch,一手动态直达): [https://github.com/HCThink/h-blog](https://github.com/HCThink/h-blog) 12 | 13 | - [掘金 link](https://juejin.im/user/58f06f7a5c497d006c7bc766/shares) , [掘金 专栏](https://juejin.im/user/58f06f7a5c497d006c7bc766/posts) 14 | - [segmentfault 主页](https://segmentfault.com/u/hooperhu) 15 | 16 | __原创禁止私自转载__ 17 | 18 | --- 19 | -------------------------------------------------------------------------------- /env/index.md: -------------------------------------------------------------------------------- 1 | # 环境配置 2 | 3 | ## 开发环境 4 | 5 | - nvm 6 | - node 7 | - git 8 | - deno 9 | 10 | ## 命令行工具 11 | 12 | - https://www.jianshu.com/p/f45f64cd6cca 13 | - https://zhuanlan.zhihu.com/p/550022490 14 | - https://juejin.cn/post/6844904178075058189#heading-26 15 | 16 | ## packages manage 17 | 18 | - https://zhuanlan.zhihu.com/p/451025256 19 | 20 | ## git 21 | 22 | - https://github.com/GitAlias/gitalias 23 | -------------------------------------------------------------------------------- /interesting/excellentBlog.md: -------------------------------------------------------------------------------- 1 | # 精选博客 2 | 3 | > 读书破万卷 4 | 5 | 6 | ## 曲苑杂坛 7 | 8 | - [好站:前端收藏夹](http://collect.w3ctrain.com/?from=https://github.com/HCThink/h-blog) 9 | - [「荐」 learn anything](https://learn-anything.xyz/?from=https://github.com/HCThink/h-blog) 10 | 11 | - [package.json 全解析](https://www.cnblogs.com/tzyy/p/5193811.html?from=https://github.com/HCThink/h-blog) 12 | 13 | - [编写高质量代码:改善JavaScript程序的188个建议](https://book.2cto.com/201211/9239.html?from=https://github.com/HCThink/h-blog) 14 | - [js函数式编程指南](https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/ch4.html#不仅仅是双关语咖喱?from=https://github.com/HCThink/h-blog) 15 | - [js 中实用小技巧](https://segmentfault.com/a/1190000012405845?from=https://github.com/HCThink/h-blog) 16 | - [0.1 + 0.2 = ?](http://www.cnblogs.com/hustskyking/p/ieee754-operation-in-js.html?from=https://github.com/HCThink/h-blog) 17 | 18 | - [Koa2进阶学习笔记](https://github.com/chenshenhai/koa2-note?from=https://github.com/HCThink/h-blog) 19 | - [基于Koa2搭建Node.js实战项目教程](https://github.com/ikcamp/koa2-tutorial?from=https://github.com/HCThink/h-blog) 20 | 21 | - [ES6 Generator函数实现协同程序](https://github.com/Jocs/jocs.github.io/issues/12?from=https://github.com/HCThink/h-blog) 22 | - [荐 协程(Coroutine)-ES中关于Generator/async/await的学习思考](https://blog.csdn.net/shenlei19911210/article/details/61194617?from=https://github.com/HCThink/h-blog) 23 | 24 | - [git 学习工具](https://learngitbranching.js.org/?demo&from=https://github.com/HCThink/h-blog) 25 | 26 | - [chrome 调试相关(系列)](https://juejin.im/post/5c0ee12551882545e24ef291?utm_source=gold_browser_extension&from=https://github.com/HCThink/h-blog) 27 | 28 | - [从0开始,5分钟创建一个Spring Boot + Angular/React应用](https://zhuanlan.zhihu.com/p/53182228) 29 | 30 | 31 | ## 系列博客 32 | 33 | - [小胡子哥](http://www.barretlee.com/?from=https://github.com/HCThink/h-blog) 34 | - [穆乙](http://www.cnblogs.com/pigtail/?from=https://github.com/HCThink/h-blog) 35 | - [haorooms](https://www.haorooms.com/?from=https://github.com/HCThink/h-blog) 36 | -------------------------------------------------------------------------------- /interesting/hehe.md: -------------------------------------------------------------------------------- 1 | # 有趣的注释,总有你喜欢的那款 2 | 3 | 需要源码的请点击这里   💢   ️ 👉 👉 👉🏻 👉🏻    [__⭕ 源码链接 ⭕__](./hehe.js) 4 | 5 | 需要源码的请点击这里   💢   ️ 👉 👉 👉🏻 👉🏻    [__⭕ 源码链接 ⭕__](./hehe.js) 6 | 7 | 需要源码的请点击这里   💢   ️ 👉 👉 👉🏻 👉🏻    [__⭕ 源码链接 ⭕__](./hehe.js) 8 | 9 | 10 | > 好看的代码千篇一律,有趣的注释万里挑一, 多图预警! 11 | 12 | 13 | 14 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h1.png) 15 | 16 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h2.png) 17 | 18 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h3.png) 19 | 20 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h4.png) 21 | 22 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h5.png) 23 | 24 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h6.png) 25 | 26 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h7.png) 27 | 28 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h8.png) 29 | 30 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h9.png) 31 | 32 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h10.png) 33 | 34 | ![好看的代码千篇一律,有趣的注释万里挑一](../resource/img/hehe/h11.png) 35 | -------------------------------------------------------------------------------- /interesting/in1.md: -------------------------------------------------------------------------------- 1 | # 怎么使 if(aᅠ==1 && a== 2 && ᅠa==3) 返回 true? 2 | 3 | __注意: 如下代码可能存在不可见部分: ,如果想看效果,务必 __copy__ 源码运行, 而不要自己手敲 __ 4 | 5 | - toString / valueOf : 最直接的方案 6 | ```javascript 7 | let a = { 8 | i: 1, 9 | toString: function () { 10 | return a.i++; 11 | } 12 | } 13 | ``` 14 | 15 | - getter : 新式 16 | ```javascript 17 | var i = 0; 18 | 19 | with({ 20 | get a() { 21 | return ++i; 22 | } 23 | }) { 24 | if (a == 1 && a == 2 && a == 3) 25 | console.log("wohoo"); 26 | } 27 | 28 | // or 29 | 30 | Object.defineProperty(window, 'a', { 31 | get: function() { 32 | return ++val; 33 | } 34 | }); 35 | 36 | // or 37 | 38 | window.__defineGetter__( 'a', function(){ 39 | if( typeof i !== 'number' ){ 40 | // define i in the global namespace so that it's not lost after this function runs 41 | i = 0; 42 | } 43 | return ++i; 44 | }); 45 | ``` 46 | 47 | - es6 Proxy 48 | ```javascript 49 | var a = new Proxy({ i: 0 }, { 50 | get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name], 51 | }); 52 | console.log(a == 1 && a == 2 && a == 3); 53 | ``` 54 | 55 | - 别具匠心 56 | ```javascript 57 | // This works because == invokes toString which calls .join for Arrays. 58 | a = [1,2,3]; 59 | a.join = a.shift; 60 | console.log(a == 1 && a == 2 && a == 3); 61 | ``` 62 | 63 | - 新潮 64 | ```javascript 65 | // Another solution, using Symbol.toPrimitive which is an ES6 equivalent of toString/valueOf 66 | let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)}; 67 | 68 | console.log(a == 1 && a == 2 && a == 3); 69 | ``` 70 | 71 | - amazed 最让我吃惊的方案 72 | ```javascript 73 | var aᅠ = 1; 74 | var a = 2; 75 | var ᅠa = 3; 76 | if(aᅠ ==1 && a == 2 && ᅠa ==3) { 77 | console.log("Why hello there!") 78 | } 79 | 80 | // let aᅠ = 1; 81 | // let a = 2; 82 | // let ᅠa = 3; 83 | // https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true# 84 | // 这里三个是不同的变量,第一个和第三个 a 前后的空白字符不是空格,Unicode FFA0 85 | // 请注意if 语句中的奇怪间距。它是半宽度韩文=,=。这是一个 Unicode 空格字符,但是 ECMAScript 不将其解释为一个空格 —— 这意味着它是一个有效的标识符。因此有三个完全不同的变量,一个是a后加半宽度韩文,一个是a, 一个是a前加半宽度韩文。 86 | 87 | ``` 88 | 89 | - 覆盖式: 原理同上, if 后面有一个字符. 在 chrome 调试中可以看得到, 你没法覆盖掉真正的 if. 所以大括号必须新起一行 90 | ```javascript 91 | if‌=()=>!0; 92 | 93 | var i = 1; 94 | if‌(i == 1 && i == 2 && i == 3) 95 | { 96 | console.log(i) 97 | } 98 | ``` 99 | 100 | 101 | - 拓展: 数字变量名 102 | ```javascript 103 | var a = 1; 104 | var ᅠ1 = a; 105 | var ᅠ2 = a; 106 | var ᅠ3 = a; 107 | console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 ); 108 | ``` 109 | -------------------------------------------------------------------------------- /interesting/in2.md: -------------------------------------------------------------------------------- 1 | # 巧用异步事件队列. 2 | 3 | - Q: 如果数组列表太大,以下递归代码将导致堆栈溢出。你如何解决这个问题,仍然保留递归模式 4 | 5 | ```javascript 6 | let list = readHugeList(); 7 | let nextListItem = function() { 8 | let item = list.pop(); 9 | if (item) { 10 | // process the list item... 11 | nextListItem(); 12 | } 13 | }; 14 | ``` 15 | 16 | - A: 堆栈溢出被消除,因为事件循环处理递归,而不是调用堆栈。当nextListItem运行时,如果item不为null,则将超时函数(nextListItem)推送到事件队列,并且函数退出,从而使调用堆栈清零。当事件队列运行超时事件时,将处理下一个项目,并设置一个计时器以再次调用nextListItem。因此,该方法从头到尾不经过直接递归调用即可处理,因此调用堆栈保持清晰,无论迭代次数如何。 17 | 18 | 简而言之就是,函数之行到 timeout 时, 将 nextListItem 放入宏任务队列(原本应该是递归操作), 利用时间循环处理, 然后继续之行之后的代码. 在执行结束之后, 将结束该函数的函数栈. 主栈空了空了之后, 进入宏任务队列, 由时间循环机制处理刚刚放入的 nextListItem . 如此一来, 就没有嵌套函数栈了. 19 | 20 | ```javascript 21 | let list = readHugeList(); 22 | let nextListItem = function() { 23 | let item = list.pop(); 24 | if (item) { 25 | // process the list item... 26 | setTimeout(nextListItem, 0); 27 | } 28 | }; 29 | ``` 30 | 31 | 备注:方案缺点也很明显,所有方案脱离场景说好坏都是耍流氓, 可以多一种思路。仅此而已。 32 | -------------------------------------------------------------------------------- /js/syncAndAsync/callback/lib/cb-ctrlreceive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: hooper 3 | * @Date: 2017-Nov-21 1:28:27 pm 4 | * @Email: hooper.echo@gmail.com, hucheng-rj@ofo.com 5 | * @Filename: cb-dealsync.js 6 | * @Last modified by: hucheng-rj 7 | * @Last modified time: 2017-Nov-22 11:25:26 am 8 | * 9 | * @desc cb 处理多异步场景方案2: 控制处理顺序. 10 | */ 11 | 12 | function log(data, newLine) { 13 | console.log(JSON.stringify(Object(data), null, 4)); 14 | newLine && console.log(); 15 | } 16 | 17 | const sender = []; 18 | function ajax(url, time) { 19 | return function(cb) { 20 | sender.push(url); 21 | setTimeout(function() { 22 | const data = { 23 | from: url, 24 | reso: 'ok' 25 | }; 26 | 27 | dealReceive({url, cb, data}); 28 | }, time); 29 | } 30 | } 31 | 32 | 33 | const receiver = {}; 34 | function dealReceive({url, cb, data}) { 35 | receiver[url] = {cb, data}; 36 | for (var i = 0; i < sender.length; i++) { 37 | let operate = receiver[sender[i]]; 38 | if(typeof operate === 'object') { 39 | operate.cb.call(null, operate.data); 40 | } else { 41 | return; 42 | } 43 | } 44 | } 45 | 46 | const A = ajax('/ofo/a', 4000); 47 | 48 | const B = ajax('/ofo/b', 600); 49 | 50 | const C = ajax('/ofo/c', 2000); 51 | 52 | 53 | A(function (a) { 54 | log(a); 55 | }); 56 | 57 | B(function (b) { 58 | log(b); 59 | }); 60 | 61 | C(function (c) { 62 | log(c); 63 | }); 64 | 65 | // {"from":"/ofo/a","reso":"ok"} 66 | // {"from":"/ofo/b","reso":"ok"} 67 | // {"from":"/ofo/c","reso":"ok"} 68 | -------------------------------------------------------------------------------- /js/syncAndAsync/callback/lib/cb-ctrlsend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: hooper 3 | * @Date: 2017-Nov-21 1:28:27 pm 4 | * @Email: hooper.echo@gmail.com, hucheng-rj@ofo.com 5 | * @Filename: cb-dealsync.js 6 | * @Last modified by: hucheng-rj 7 | * @Last modified time: 2017-Nov-21 2:52:01 pm 8 | * 9 | * @desc cb 处理多异步场景方案1: 控制发出顺序. 10 | */ 11 | 12 | 13 | function log(data, newLine) { 14 | console.log(JSON.stringify(Object(data))); 15 | newLine && console.log(); 16 | } 17 | 18 | function ajax(url) { 19 | return function (cb) { 20 | setTimeout(function() { 21 | cb({ 22 | url 23 | }); 24 | }, Math.random() * 3000); 25 | } 26 | } 27 | 28 | 29 | const A = ajax('/ofo/a'); 30 | 31 | const B = ajax('/ofo/b'); 32 | 33 | const C = ajax('/ofo/c'); 34 | 35 | 36 | log('ajax A send...'); 37 | A(function (a) { 38 | log('ajax A receive...'); 39 | log(a, true); 40 | 41 | log('ajax B send...'); 42 | B(function (b) { 43 | log('ajax B receive...'); 44 | log(b, true); 45 | 46 | log('ajax C send...'); 47 | C(function (C) { 48 | log('ajax C receive...'); 49 | log(C); 50 | }); 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /js/syncAndAsync/callback/readme.old.md: -------------------------------------------------------------------------------- 1 | # callback 回调 2 | 3 | - 回调是解决异步问题比较老的一种方式, 也是使用很多的一种方式.我们大致从一些维度认识一下回调 4 | 5 | - 回调是一种处理特定问题的模式, 伴随着函数式编程而生. 函数式编程最主要的技术之一就是回调函数 6 | - 函数作为一等功民的[函数式编程](/programming-paradigm/index.md)中, 函数可以作为参数进行传递(回调), 也可以作为返回值提供给外部(函数生成器: thunk, currying). 7 | - 当一个函数作为主调函数的参数时, 它往往会在特定的时间和场景(上下文)执行. 8 | - 执行过程中,回调函数选择性接收函数内部的数据, 或者状态(内存), 经过处理选择性返回,或者改变状态. 9 | - 回调函数不是由该函数实现方来直接调用,而是在特定的时间或者在特定的条件下由另外一方调用的,对某一事件或条件进行响应。 10 | - 这个机制很类似 hook, 我们称之为回调. 11 | - In computer programming, a callback is a reference to a piece of executable code that is passed as an argument to other code. --维基百科 12 | 13 | 14 | --- 15 | 16 | 17 | 26 | --- 27 | 28 | 29 | 30 | --- 31 | 32 | ## chat shell 33 | > '浮于表层的闲谈'. 选看.一直找不到比较合适的词汇.看官见谅 34 | 35 | - 你觉得回调很 low ,可能是因为: 实现回调函数就像传递一般的参数变量一样简单.由于函数式编程极好的支持,以至于这项技术使用基本没有障碍. 36 | - 没有使用障碍导致回调的滥用, 大部分问题都用了简单的回调堆叠来解决. 实际上我们有很多基于回调的模式可以避免这些问题.比如: cps, cps 进一步转化为 thunk.等等. 37 | 38 | - C++, C 中的回调: 回调函数就是一个通过函数指针调用的函数。如果把函数的指针作为函数参数传递给另一个函数,当这个函数指针作为调用者而指向某个函数时,这就是回调函数。 39 | - 回调和异步没关系. 回调能处理多种场景,异步是其中之一. 40 | - 当我们遇到回调无底洞的时候,无需惊慌,其实这根本不是什么问题: 因为同样有协程和 monad 无底洞。因为如果你把任何一个抽象使用地足够频繁的话,都同样会创造一个无底洞。 41 | 42 | > 说了这么多,回调到底有没有问题呢? 答案是有, 而且很大. 43 | 44 | - 使用回调处理异步往往意味着,你舍弃了返回值,而使用回调接收异步操作结果. 而这正是用回调风格来编程会很困难的根本原因: 回调风格不返回任何值,所以难以组合[函数式编程中函数有良好的输入和输出是函数可以组合的根本]。 45 | - 一个没有返回值的函数执行的效果其实是利用它的副作用 46 | - 一个没有返回值和利用副作用的函数其实就是一个黑洞。 47 | - 所以,使用回调风格来编程无法避免会是指令式的,它实际上是通过把一系列严重依赖于副作用的操作安排好执行顺序,而不是通过函数的调用来把输入输出值对应好。 48 | - 如果你是通过人手组织程序执行流程, 而不是靠理顺值的关系来解决问题的, 是很难编写出正确的并行程序 49 | 50 | - 回调难于调试,回调的执行,你想要的结果数据以及你的代码书写逻辑存在时间上的'中断', 你的逻辑难免随着这种中断而出现断层 51 | 52 | > 为什么出现新的方案解决异步 53 | 54 | - 以往的异步处理方案, 大多是回调的变种, 或者干脆使用一些发布订阅之类的模式.但是 promise 不同 55 | - 基于 promise 的函数总是让你把函数返回值作为一个不依赖于时间的值来考虑的。当你调用一个回调风格的函数时,在你的函数调用和它的回调函数被调用之间,在程序里面我们没办法找到一个最终结果的表现形式. 56 | 57 | - 一种新的方案的出现,并被推为主流, 往往不是因为他有绝对的优势, 而是因为原来的方案存在不可调和的问题. 58 | 59 | 60 | > 回调的优化方案 61 | 62 | ## 引用&参考 63 | 64 | - [http://blog.csdn.net/luozhonghua2014/article/details/45651659](http://blog.csdn.net/luozhonghua2014/article/details/45651659) 65 | -[大神博客https://segmentfault.com/a/1190000000356347](https://segmentfault.com/a/1190000000356347) 66 | -------------------------------------------------------------------------------- /js/syncAndAsync/cpsThunk/code/thunk.1.js: -------------------------------------------------------------------------------- 1 | { 2 | // sps 3 | const squ = (arg1) => arg1() ** 2 4 | 5 | const getArg = (n, fn) => fn(n); 6 | 7 | let n = 10; 8 | const re = squ(getArg.bind(null, n, (n) => n + 1)); 9 | 10 | console.log(re); 11 | 12 | } 13 | 14 | { 15 | // thunk 16 | const squ = (arg1) => arg1() ** 2 17 | 18 | const getArg = (n, fn) => fn(n); 19 | const getArgThunk = thunkIfy(getArg); 20 | 21 | function thunkIfy(getArg) { 22 | return (n) => { 23 | return (fn) => () => getArg(n, fn); 24 | } 25 | } 26 | 27 | let n = 10; 28 | const re = squ(getArgThunk(n)(() => n + 1)); 29 | 30 | console.log(re); 31 | } 32 | -------------------------------------------------------------------------------- /js/syncAndAsync/cpsThunk/code/thunk.2.js: -------------------------------------------------------------------------------- 1 | function ajax(url, cb) { 2 | console.log(url); 3 | setTimeout(() => { 4 | cb({ url, code: 200 }); 5 | }, 200) 6 | } 7 | 8 | // 多个异步会干扰, 所以执行文件的时候 可以添加参数 1, 2, 3, eg: node node thunk.2.js 2 执行第二个模块 普通 thunk 9 | const nodeArgs = +(process.argv.slice(2)[0] || 1); 10 | 11 | nodeArgs === 1 && (() => { 12 | // 回调式 13 | ajax('http://xxx.com/1', (data) => { 14 | ajax('http://xxx.com/2', (data) => { 15 | ajax('http://xxx.com/2', (data) => { 16 | console.log('cb do something...'); 17 | }); 18 | }); 19 | }) 20 | })() 21 | 22 | 23 | nodeArgs === 2 && (() => { 24 | // 普通 thunk 25 | function thunkIfy(fn) { 26 | return (...args) => (cb) => fn.call(null, ...args, cb); 27 | } 28 | 29 | const thAjax = thunkIfy(ajax); 30 | const ajax1 = thAjax('http://xxx.com/1'); 31 | const ajax2 = thAjax('http://xxx.com/2'); 32 | const ajax3 = thAjax('http://xxx.com/3'); 33 | 34 | ajax1((data1) => { 35 | ajax2((data2) => { 36 | ajax3((data3) => { 37 | console.log('thunk cb do something...'); 38 | }); 39 | }); 40 | }); 41 | })(); 42 | -------------------------------------------------------------------------------- /js/syncAndAsync/generator/code/generator.1.ts: -------------------------------------------------------------------------------- 1 | namespace gen1 { 2 | Array.prototype['iterator'] = function* iterator(array: number[] = this) { 3 | let index: number = 0; 4 | while (index < array.length) { 5 | yield array[index++]; 6 | } 7 | } 8 | 9 | const fbnq: number[] = [1, 1, 2, 3, 5, 8, 13, 21]; 10 | 11 | // @ts-ignore 12 | let iteratorGen: Generator = fbnq.iterator(); 13 | 14 | let n = iteratorGen.next(); 15 | while (!n.done) { 16 | console.log(n.value); 17 | n = iteratorGen.next(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /js/syncAndAsync/generator/code/generator.2.ts: -------------------------------------------------------------------------------- 1 | namespace gen2 { 2 | const Log = console.log; 3 | 4 | // 柯里化通式 5 | function currying (fn: Function, ...args) { 6 | return (...innargs) => fn(...args, ...innargs); 7 | } 8 | 9 | /** 10 | * generator 无限生成式 通用处理形如 A 的函数 11 | * 函数 A 描述 12 | * 函数描述的是某个无穷数列中。 13 | * 通过通用方式推导能得出数列中任意一项。 14 | * 比如: 斐波那契竖列, 阶乘, 等等。 15 | * 16 | * @param generator 17 | * @param n 18 | * @param list 19 | */ 20 | function dealGenerator(generatorFn: GeneratorFunction, n: number, list: boolean = false): number | number[] { 21 | const generator: Generator = generatorFn(); 22 | let index: number = 0; 23 | let re: IteratorResult = generator.next(); 24 | const reList: number[] = [re.value]; 25 | 26 | while (++index < n && !re.done) { 27 | re = generator.next(re); 28 | reList.push(re.value); 29 | } 30 | 31 | return list ? reList : re.value; 32 | } 33 | 34 | // 斐波那契数列生成器: f(n) = f(n-1) + f(n-2) 35 | function* fib() { 36 | let [x, y]: [number, number] = [0, 1]; 37 | while (true) { 38 | [x, y] = [y, x + y]; 39 | yield x; 40 | } 41 | } 42 | 43 | // 三角数: fn = n*(n+1)/2 44 | function* triangle() { 45 | let x: number = 1; 46 | while (true) { 47 | yield (x * (x + 1)) / 2; 48 | x ++; 49 | } 50 | } 51 | 52 | // 正方形数: fn = n ** 2 53 | function* square() { 54 | let x: number = 1; 55 | while (true) { 56 | yield x ** 2; 57 | x ++; 58 | } 59 | } 60 | 61 | // 阶乘: fn = n! 62 | function* factorial() { 63 | let x: number = 1; 64 | let fac: number = 1; 65 | while (true) { 66 | yield fac; 67 | fac = fac * ++x; 68 | } 69 | } 70 | 71 | 72 | // 斐波那契数列生成器 柯里化 73 | const fibGen = currying(dealGenerator, fib); 74 | // 三角数 柯里化 75 | const triangleGen = currying(dealGenerator, triangle); 76 | // 三角数 柯里化 77 | const squareGen = currying(dealGenerator, square); 78 | // 阶乘 79 | const factorialGen = currying(dealGenerator, factorial); 80 | 81 | // 测试代码 82 | const count: number = 12; 83 | 84 | // 斐波那契数列 85 | let v: number = fibGen(count); 86 | let listv: number[] = fibGen(count, true); 87 | Log(v, listv); 88 | 89 | // 三角数 90 | v = triangleGen(count, true); 91 | Log(v) 92 | 93 | // 正方形数 94 | v = squareGen(count, true); 95 | Log(v) 96 | 97 | // 阶乘 98 | v = factorialGen(count, true); 99 | Log(v) 100 | } 101 | -------------------------------------------------------------------------------- /js/syncAndAsync/generator/code/generator.3.ts: -------------------------------------------------------------------------------- 1 | 2 | const Log = console.log; 3 | 4 | namespace gen3 { 5 | /** 6 | * generator 入参和返回。 7 | */ 8 | function x10(n: number): number { 9 | return 10 * n; 10 | } 11 | 12 | function* fn(n: number) { 13 | // yield x10(n) + 10 结果为:30, 下次 next 时传入的值做了 +10, 则 g1 值为: 40 14 | let g1 = yield x10(n) + 10; 15 | Log(g1); // 40 16 | // 同理: (yield x10(g1)) 结果为: 40 * 10 = 400, 下次 next 时传入的值: 400 + 10 = 410 17 | // 代入中断的点: g1 = 410(yield x10(g1)) + 10 = 420 18 | g1 = (yield x10(g1)) + 10; 19 | Log(g1); // 420 20 | } 21 | 22 | const fnGenx: Generator = fn(2); 23 | let genObj = fnGenx.next(100); // 第一次入参会被丢弃, 因为他没有上一个 yield 24 | 25 | while (!genObj.done) { 26 | Log("outer: ", genObj.value); 27 | genObj = fnGenx.next(genObj.value + 10); 28 | } 29 | } 30 | 31 | Log() 32 | 33 | namespace gen3_1 { 34 | function* createIterator() { 35 | let first = yield 1; 36 | let second = yield first + 2; // 4 + 2 37 | // first =4 是next(4)将参数赋给上一条的 38 | yield second + 3; // 5 + 3 39 | } 40 | 41 | let iterator = createIterator(); 42 | 43 | Log(iterator.next()); // "{ value: 1, done: false }" 44 | Log(iterator.next(4)); // "{ value: 6, done: false }" 45 | Log(iterator.next(5)); // "{ value: 8, done: false }" 46 | Log(iterator.next()); // "{ value: undefined, done: true }" 47 | } 48 | -------------------------------------------------------------------------------- /resource/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/bg.png -------------------------------------------------------------------------------- /resource/img/ToObject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/ToObject.png -------------------------------------------------------------------------------- /resource/img/base.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/base.1.png -------------------------------------------------------------------------------- /resource/img/generator.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/generator.1.png -------------------------------------------------------------------------------- /resource/img/hehe/h1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h1.png -------------------------------------------------------------------------------- /resource/img/hehe/h10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h10.png -------------------------------------------------------------------------------- /resource/img/hehe/h11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h11.png -------------------------------------------------------------------------------- /resource/img/hehe/h2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h2.png -------------------------------------------------------------------------------- /resource/img/hehe/h3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h3.png -------------------------------------------------------------------------------- /resource/img/hehe/h4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h4.png -------------------------------------------------------------------------------- /resource/img/hehe/h5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h5.png -------------------------------------------------------------------------------- /resource/img/hehe/h6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h6.png -------------------------------------------------------------------------------- /resource/img/hehe/h7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h7.png -------------------------------------------------------------------------------- /resource/img/hehe/h8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h8.png -------------------------------------------------------------------------------- /resource/img/hehe/h9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/hehe/h9.png -------------------------------------------------------------------------------- /resource/img/jsx.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/jsx.1.png -------------------------------------------------------------------------------- /resource/img/lee258.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/lee258.jpeg -------------------------------------------------------------------------------- /resource/img/middleware.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/middleware.gif -------------------------------------------------------------------------------- /resource/img/operate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/operate.png -------------------------------------------------------------------------------- /resource/img/toNumber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/toNumber.png -------------------------------------------------------------------------------- /resource/img/wk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/resource/img/wk.png -------------------------------------------------------------------------------- /source/Lodash/Lodash-4.17.10/runInContext-main.md: -------------------------------------------------------------------------------- 1 | ## runInContext lodash main part 2 | 3 | > 数组相关操作, 或直接操作数组, 或操作结果为数组, 偏工具操作, 大多服务于 runInContext 中挂载在 lodash 上的操作 4 | 5 | ```javascript 6 | 7 | ``` 8 | -------------------------------------------------------------------------------- /source/Lodash/demo/lodash-this.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const root = this; 3 | // 利用 Function 中的代码始终在全局域执行. 4 | const root1 = Function('return this')(); 5 | 6 | console.log(root, root === global, root1 === global); 7 | }.call({a: 2})) -------------------------------------------------------------------------------- /source/Underscore.js/demo/is-fun.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: baidu 3 | * @Date: 2017-08-22T16:56:42+08:00 4 | * @Email: hucheng@baidu.com 5 | * @Filename: is-Fun.js 6 | * @Last modified by: baidu 7 | * @Last modified time: 2017-08-22T16:56:53+08:00 8 | */ 9 | 10 | 11 | class UN { 12 | constructor(...arg) { 13 | this.fn(...arg); 14 | } 15 | 16 | fn(...arg) { 17 | [ 18 | 'Arguments', 19 | 'Function', 20 | 'String', 21 | 'Number', 22 | 'Date', 23 | 'RegExp', 24 | 'Error' 25 | ].map(function(name) { 26 | // debugger; 27 | this['is' + name] = function(obj) { 28 | return Object.prototype.toString.call(obj) === '[object ' + name + ']'; 29 | }; 30 | }.bind(this)); 31 | } 32 | } 33 | 34 | console.log(new UN()); -------------------------------------------------------------------------------- /source/Underscore.js/demo/noConflict.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const root = typeof self == 'object' && self.self === self && self || 4 | typeof global == 'object' && global.global === global && global || 5 | this || {} 6 | 7 | { 8 | const _ = { 9 | name: 'lib a', 10 | version: '3.0.0', 11 | } 12 | 13 | // .... 14 | 15 | root._ = _ 16 | } 17 | 18 | { 19 | const previousLib = root._ 20 | 21 | const _ = { 22 | name: 'lib b', 23 | version: '1.0.0', 24 | } 25 | _.noConflict = function () { 26 | root._ = previousLib 27 | return this 28 | } 29 | 30 | root._ = _ 31 | } 32 | 33 | console.log(global._); // lib b 覆盖了 a 库 34 | // { name: 'lib b', version: '1.0.0', noConflict: [Function] } 35 | 36 | const LibB = _.noConflict() 37 | console.log(global._, LibB); 38 | // { name: 'lib a', version: '3.0.0' } { name: 'lib b', version: '1.0.0', noConflict: [Function] } 39 | 40 | 41 | -------------------------------------------------------------------------------- /source/delegates/readme.md: -------------------------------------------------------------------------------- 1 | # Delegates(TJ) 2 | 3 | [homepage](https://github.com/tj/node-delegates) 4 | 5 | > Delegates 可以帮我们方便快捷地使用设计模式当中的委托模式(Delegation Pattern),即外层暴露的对象将请求委托给内部的其他对象进行处理. 6 | 7 | 8 | ## 基础使用 9 | 10 | 基本用法就是将内部对象的变量或者函数绑定在暴露在外层的变量上,直接通过 delegates 方法进行如下委托。 11 | 12 | 主要 api 也很简单明了: 13 | 14 | - Delegate(proto, prop): 15 | Creates a delegator instance used to configure using the prop on the given proto object. (which is usually a prototype) 16 | - getter:外部对象可以直接访问内部对象的值 17 | - setter:外部对象可以直接修改内部对象的值 18 | - access:包含 getter 与 setter 的功能 19 | - method:外部对象可以直接调用内部对象的函数 20 | 21 | ```js 22 | const delegate = require('delegates'); 23 | 24 | const School = { 25 | Class: { 26 | id: 10000, 27 | name: 'B-3', 28 | level: '高中', 29 | studentList: [], 30 | tech(){ 31 | // .... tech 32 | }, 33 | put(student){ 34 | this.student.push(student); 35 | } 36 | } 37 | }; 38 | 39 | const { Class: classes } = School; 40 | 41 | delegate(School, 'Class') 42 | .method('tech') 43 | .access('name') 44 | .getter('id') 45 | .setter('level'); 46 | 47 | // 委托之后就可以使用 School 操作 School.Class 上被委托的属性 48 | console.log(School.name, School.id, School.level, 'level' in School, 'put' in School, 'tech' in School); 49 | console.log(classes.name, classes.id, classes.level, 'level' in classes, 'put' in classes, 'tech' in classes); 50 | 51 | School.level = '重点高中'; 52 | console.log(School.level, School.Class.level); 53 | 54 | // B-3 10000 undefined true false true 55 | // B-3 10000 高中 true true true 56 | // undefined '重点高中' 57 | ``` 58 | 59 | > fluent 60 | ```js 61 | const delegate = require('delegates'); 62 | 63 | const obj = { 64 | settings: { 65 | env: 'development' 66 | } 67 | }; 68 | 69 | delegate(obj, 'settings').fluent('env'); 70 | 71 | console.log(typeof obj.env, obj.env()); 72 | console.log(obj.env('setting production')); 73 | console.log(obj.env(), obj.env() === obj.settings.env); 74 | // function development 75 | // { settings: { env: 'setting production' }, env: [Function] } 76 | // setting production true 77 | ``` 78 | 79 | > auto 80 | ```js 81 | const delegate = require('../index'); 82 | 83 | const obj = { 84 | main: { 85 | a: 1, 86 | b: 2, 87 | c() { 88 | 89 | } 90 | } 91 | } 92 | 93 | delegate.auto(obj, obj.main, 'main'); 94 | console.log(obj.a, obj.main.a, obj.b, obj.c === obj.main.c); 95 | ``` 96 | 97 | 98 | ## 源码分析 99 | 100 | __所有源码分析均以「注释」的方式提供在如下源码文件中【私以为这么做相对好一些,有更好的方式欢迎告知】__ 101 | 102 | 源码参考:[delegates.js source](./index.js) 103 | 104 | 105 | ## 问题 106 | 107 | 使用已经废弃的 api 108 | 109 | `Delegator.prototype.getter` , `Delegator.prototype.setter` 两个 api 实现中使用了 `__defineGetter__ or __defineSetter__` , 这两个 api 是非标准 api ,并且目前已经明确表明废弃了。 110 | 111 | 修正方案: 112 | 113 | ```js 114 | Object.defineProperty(proto, name, { 115 | get() { 116 | return this[target][name]; 117 | } 118 | }); 119 | ``` 120 | 121 | __TJ 已经不更新,此库慎用__ 122 | 123 | ## koa 使用此库。 124 | 125 | [koa 源码分析](../koa2/readme.md) 126 | 127 | ## 参考 & 鸣谢 128 | 129 | - https://github.com/tj/node-delegates 130 | - https://juejin.im/post/5b9339136fb9a05d3634ba13 131 | -------------------------------------------------------------------------------- /source/koa2/code/koa.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/source/koa2/code/koa.zip -------------------------------------------------------------------------------- /source/koa2/code/koa/app.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa'; 2 | import https from 'https'; 3 | import open from 'open'; 4 | 5 | const Log = console.log; 6 | const App = new Koa(); 7 | 8 | App.use(async (ctx, next) => { 9 | ctx.request.accepts('text/html'); 10 | // 检查 encodings 是否可以接受 11 | ctx.acceptsEncodings(['gzip', 'deflate', 'identity']); 12 | ctx.acceptsCharsets('utf-8'); 13 | 14 | Log('mid1 start...'); 15 | await next(); 16 | Log('mid1 end...'); 17 | }); 18 | 19 | App.use(async (ctx, next) => { 20 | ctx.body = '

Hello World!

-- 鲁迅
'; 21 | Log('mid2 start...'); 22 | await next(); 23 | Log('mid2 end...'); 24 | }); 25 | 26 | 27 | App.use((ctx, next) => { 28 | Log('mid3...'); 29 | debugger; 30 | Log(ctx.inspect()); 31 | }); 32 | 33 | // 服务监听: 两种方式。 34 | App.listen(3000); // 语法糖 35 | // http.createServer(app.callback()).listen(3000); 36 | https.createServer(App.callback()).listen(3001, () => { 37 | // open('http://localhost:3000') 38 | }); 39 | 40 | // 如下为执行顺序, 实际上 http 会握手,所以输出多次 41 | // 如下执行特征也就是洋葱圈, 实际上熟悉 async、await 则不会比较意外。 42 | // mid1 start... 43 | // mid2 start... 44 | // mid3... 45 | // mid2 end... 46 | // mid1 end... 47 | -------------------------------------------------------------------------------- /source/koa2/code/koa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "koa", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "main": "index.js", 7 | "scripts": { 8 | "start": "node --experimental-modules --loader ./script/custom-loader.mjs ./app.js", 9 | "dev": "node --experimental-modules --loader ./script/custom-loader.mjs ./app.js", 10 | "debug": "ndb --experimental-modules --loader ./script/custom-loader.mjs ./app.js", 11 | "tree": "tree -I node_modules", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "dependencies": { 15 | "koa": "^2.6.1", 16 | "open": "^0.0.5" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/HCThink/h-blog.git" 21 | }, 22 | "devDependencies": {}, 23 | "author": "hooper.echo@gmail.com", 24 | "homepage": "https://github.com/HCThink/h-blog", 25 | "license": "ISC" 26 | } 27 | -------------------------------------------------------------------------------- /source/koa2/code/koa/script/custom-loader.mjs: -------------------------------------------------------------------------------- 1 | import url from 'url'; 2 | import path from 'path'; 3 | import process from 'process'; 4 | import fs from 'fs'; 5 | 6 | // 从package.json中 7 | // 的dependencies、devDependencies获取项目所需npm模块信息 8 | const ROOT_PATH = process.cwd(); 9 | const PKG_JSON_PATH = path.join(ROOT_PATH, 'package.json'); 10 | const PKG_JSON_STR = fs.readFileSync(PKG_JSON_PATH, 'binary'); 11 | const PKG_JSON = JSON.parse(PKG_JSON_STR); 12 | // 项目所需npm模块信息 13 | const allDependencies = { 14 | ...PKG_JSON.dependencies || {}, 15 | ...PKG_JSON.devDependencies || {} 16 | } 17 | 18 | //Node原生模信息 19 | const builtins = new Set( 20 | Object.keys(process.binding('natives')).filter((str) => 21 | /^(?!(?:internal|node|v8)\/)/.test(str)) 22 | ); 23 | 24 | // 文件引用兼容后缀名 25 | const JS_EXTENSIONS = new Set(['.js', '.mjs']); 26 | const JSON_EXTENSIONS = new Set(['.json']); 27 | 28 | // debugger; 29 | export function resolve(specifier, parentModuleURL = 'file:\/\/', defaultResolve) { 30 | // 判断是否为Node原生模块 31 | if (builtins.has(specifier)) { 32 | return { 33 | url: specifier, 34 | format: 'builtin' 35 | }; 36 | } 37 | 38 | // 判断是否为npm模块 39 | if (allDependencies && typeof allDependencies[specifier] === 'string') { 40 | return defaultResolve(specifier, parentModuleURL); 41 | } 42 | 43 | // 如果是文件引用,判断是否路径格式正确 44 | if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) { 45 | throw new Error( 46 | `imports must begin with '/', './', or '../'; '${specifier}' does not`); 47 | } 48 | 49 | // 判断是否为*.js、*.mjs、*.json文件 50 | /** 51 | * 之前看 node 设计缺陷中说过 require or import 引用为了便利, 可以省略后缀让引擎去决策加载是个很大的缺陷, 52 | * 那时候还没有体会,这里表现的比较突出,比如: 53 | * `import Promise from './es6-promise/promise';` 54 | * 这个语句其实带来的语义确实很不明确, 而且你需要额外的代码去做判断兼容, 确实是比较不好的设计。 55 | * 56 | * 这里取巧默认 import 引入的是 js。 57 | */ 58 | 59 | let resolved = new url.URL(specifier, parentModuleURL); 60 | let ext = path.extname(resolved.pathname); 61 | if (!ext) { 62 | if (fs.existsSync(`${resolved.pathname}.js`)) { 63 | ext = '.js' 64 | resolved = new url.URL(`${specifier}.js`, parentModuleURL); 65 | } else { 66 | throw new Error( 67 | `no such file: ${resolved.pathname}.`); 68 | } 69 | } 70 | 71 | if (!JS_EXTENSIONS.has(ext) && !JSON_EXTENSIONS.has(ext)) { 72 | throw new Error( 73 | `Cannot load file with non-JavaScript file extension ${ext}.`); 74 | } 75 | 76 | // 如果是*.js、*.mjs文件 77 | if (JS_EXTENSIONS.has(ext)) { 78 | return { 79 | url: resolved.href, 80 | format: 'esm' 81 | }; 82 | } 83 | 84 | // 如果是*.json文件 85 | if (JSON_EXTENSIONS.has(ext)) { 86 | return { 87 | url: resolved.href, 88 | format: 'json' 89 | }; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /source/koa2/code/onionRings.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HCThink/h-blog/990530c0ebb12493968c30aba94e5924abf9b480/source/koa2/code/onionRings.zip -------------------------------------------------------------------------------- /source/koa2/code/onionRings/callStack.js: -------------------------------------------------------------------------------- 1 | function App() { 2 | this._middList = []; 3 | } 4 | 5 | App.prototype.use = function (fn) { 6 | this._middList.push(fn); 7 | } 8 | 9 | App.prototype._deal = function (index = 0) { 10 | if (index >= this._middList.length) { 11 | return false; 12 | } 13 | this._middList[index](this, this._deal.bind(this, index + 1)); 14 | } 15 | 16 | App.prototype.listen = function (port) { 17 | setTimeout(() => { 18 | this._deal(); 19 | }, Math.random() * port); 20 | } 21 | 22 | const app = new App(); 23 | 24 | app.use((ctx, next) => { 25 | console.log(1); 26 | next(); 27 | console.log(2); 28 | }) 29 | 30 | app.use((ctx, next) => { 31 | console.log(3); 32 | next(); 33 | console.log(4); 34 | }) 35 | 36 | app.use((ctx, next) => { 37 | console.log(5); 38 | next(); 39 | }) 40 | 41 | 42 | app.listen(2000); 43 | -------------------------------------------------------------------------------- /source/koa2/code/onionRings/koa-readFile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | var __generator = (this && this.__generator) || function (thisArg, body) { 11 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 12 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 13 | function verb(n) { return function (v) { return step([n, v]); }; } 14 | function step(op) { 15 | if (f) throw new TypeError("Generator is already executing."); 16 | while (_) try { 17 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 18 | if (y = 0, t) op = [op[0] & 2, t.value]; 19 | switch (op[0]) { 20 | case 0: case 1: t = op; break; 21 | case 4: _.label++; return { value: op[1], done: false }; 22 | case 5: _.label++; y = op[1]; op = [0]; continue; 23 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 24 | default: 25 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 26 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 27 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 28 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 29 | if (t[2]) _.ops.pop(); 30 | _.trys.pop(); continue; 31 | } 32 | op = body.call(thisArg, _); 33 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 34 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 35 | } 36 | }; 37 | exports.__esModule = true; 38 | // @ts-ignore 39 | var fs = require("fs"); 40 | /** 41 | * 一个外部中间件 42 | * @param file 文件名称 43 | * @param conf 配置 44 | */ 45 | function countCharacter(file, conf) { 46 | var _this = this; 47 | if (conf === void 0) { conf = { encoding: 'utf-8' }; } 48 | return function (ctx, next) { return __awaiter(_this, void 0, void 0, function () { 49 | var data; 50 | return __generator(this, function (_a) { 51 | switch (_a.label) { 52 | case 0: return [4 /*yield*/, new Promise(function (resolve, reject) { 53 | fs.readFile(file || ctx.file, conf, function (err, data) { 54 | err && reject(err); 55 | resolve({ 56 | data: data, 57 | length: data.length 58 | }); 59 | }); 60 | })]; 61 | case 1: 62 | data = _a.sent(); 63 | // 中间件的插拔很容易,所以外部中间件很多,中间件也会有各种组合,所以中间件之间不要有数据传递 64 | // 中间件的处理和数据都反馈到 ctx 上。 65 | ctx.context = data; 66 | return [4 /*yield*/, next()]; 67 | case 2: 68 | _a.sent(); 69 | return [2 /*return*/]; 70 | } 71 | }); 72 | }); }; 73 | } 74 | exports["default"] = countCharacter; 75 | //# sourceMappingURL=koa-readFile.js.map -------------------------------------------------------------------------------- /source/koa2/code/onionRings/koa-readFile.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import * as fs from 'fs'; 3 | 4 | /** 5 | * 一个外部中间件 6 | * @param file 文件名称 7 | * @param conf 配置 8 | */ 9 | export default function countCharacter(file: string, conf = { encoding: 'utf-8' }) { 10 | return async (ctx, next) => { 11 | const data = await new Promise((resolve, reject) => { 12 | fs.readFile(file || ctx.file, conf, (err, data: string) => { 13 | err && reject(err); 14 | resolve({ 15 | data, 16 | length: data.length 17 | }); 18 | }) 19 | }); 20 | 21 | // 中间件的插拔很容易,所以外部中间件很多,中间件也会有各种组合,所以中间件之间不要有数据传递 22 | // 中间件的处理和数据都反馈到 ctx 上。 23 | ctx.context = data; 24 | 25 | await next(); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /source/koa2/code/onionRings/onionRings.ts: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * node 执行: tsc onionRings.ts --lib 'es2015' --sourceMap && node onionRings.js 5 | * deno 执行: deno onionRings.ts: 因为存在文件引用, 以及 node原生模块 fs, 不建议使用 deno 执行 6 | */ 7 | 8 | import countCharacter from './koa-readFile'; 9 | 10 | namespace onionRings { 11 | interface Applicatipn { 12 | use(middleware: Function); 13 | listen(port: number); 14 | } 15 | 16 | const Log = (...any: any[]) => { 17 | // @ts-ignore 18 | console.log(...any); 19 | }; 20 | 21 | const Loop = () => {}; 22 | 23 | class App implements Applicatipn { 24 | private middList: Function[] = []; 25 | constructor() { } 26 | 27 | use(middleware: Function) { 28 | this.middList.push(middleware); 29 | } 30 | 31 | private async deal(i: number = 0) { 32 | debugger; 33 | if (i >= this.middList.length) { 34 | return false; 35 | } 36 | await this.middList[i](this, this.deal.bind(this, i + 1)); 37 | } 38 | 39 | listen(port: number) { 40 | // @ts-ignore 41 | setTimeout(() => { 42 | debugger; 43 | this.deal(); 44 | }, Math.random() * port); 45 | } 46 | } 47 | 48 | // test 49 | const app: Applicatipn = new App(); 50 | 51 | app.use(async (ctx, next) => { 52 | Log(1); 53 | await next(); 54 | Log(2); 55 | }); 56 | 57 | app.use(async (ctx, next) => { 58 | Log(3); 59 | await next(); 60 | Log(4); 61 | }); 62 | 63 | // 外部中间件 64 | app.use(countCharacter('./onionRings.ts')); 65 | 66 | app.use(async (ctx, next) => { 67 | Log(ctx.context.length); 68 | const deal = await readFile('./onionRings.ts'); 69 | Log(deal); 70 | 71 | await next(); 72 | }); 73 | 74 | app.listen(3000); 75 | 76 | function readFile(path: string, operate = { charles: 'utf-8' }) { 77 | return new Promise((resolve, reject) => { 78 | // @ts-ignore 79 | setTimeout(() => { 80 | resolve(5); 81 | }, 3000); 82 | }); 83 | } 84 | 85 | // 1 3 5 4 2 86 | } 87 | -------------------------------------------------------------------------------- /source/koa2/koa2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "koa", 3 | "version": "2.6.2", 4 | "description": "Koa web app framework", 5 | "main": "lib/application.js", 6 | "scripts": { 7 | "test": "jest", 8 | "test-cov": "jest --coverage --runInBand --forceExit", 9 | "lint": "eslint benchmarks lib test", 10 | "bench": "make -C benchmarks", 11 | "authors": "git log --format='%aN <%aE>' | sort -u > AUTHORS" 12 | }, 13 | "repository": "koajs/koa", 14 | "keywords": [ 15 | "web", 16 | "app", 17 | "http", 18 | "application", 19 | "framework", 20 | "middleware", 21 | "rack" 22 | ], 23 | "license": "MIT", 24 | "dependencies": { 25 | "accepts": "^1.3.5", 26 | "cache-content-type": "^1.0.0", 27 | "content-disposition": "~0.5.2", 28 | "content-type": "^1.0.4", 29 | "cookies": "~0.7.1", 30 | "debug": "~3.1.0", 31 | "delegates": "^1.0.0", 32 | "depd": "^1.1.2", 33 | "destroy": "^1.0.4", 34 | "error-inject": "^1.0.0", 35 | "escape-html": "^1.0.3", 36 | "fresh": "~0.5.2", 37 | "http-assert": "^1.3.0", 38 | "http-errors": "^1.6.3", 39 | "is-generator-function": "^1.0.7", 40 | "koa-compose": "^4.1.0", 41 | "koa-convert": "^1.2.0", 42 | "koa-is-json": "^1.0.0", 43 | "on-finished": "^2.3.0", 44 | "only": "~0.0.2", 45 | "parseurl": "^1.3.2", 46 | "statuses": "^1.5.0", 47 | "type-is": "^1.6.16", 48 | "vary": "^1.1.2" 49 | }, 50 | "devDependencies": { 51 | "eslint": "^3.17.1", 52 | "eslint-config-koa": "^2.0.0", 53 | "eslint-config-standard": "^7.0.1", 54 | "eslint-plugin-promise": "^3.5.0", 55 | "eslint-plugin-standard": "^2.1.1", 56 | "jest": "^20.0.0", 57 | "supertest": "^3.1.0" 58 | }, 59 | "engines": { 60 | "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" 61 | }, 62 | "files": [ 63 | "lib" 64 | ], 65 | "jest": { 66 | "testMatch": [ 67 | "**/test/!(helpers)/*.js" 68 | ], 69 | "coverageReporters": [ 70 | "text-summary", 71 | "lcov" 72 | ], 73 | "bail": true, 74 | "testEnvironment": "node" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /source/koa2/middleware/readme.md: -------------------------------------------------------------------------------- 1 | # middleware 2 | 3 | > 社区常用中间件 4 | 5 | TODO 6 | 7 | ## koa-router 8 | 9 | [koa-router](https://chenshenhai.github.io/koa2-note/note/route/koa-router.html) 10 | 11 | https://github.com/ikcamp/koa2-tutorial 12 | --------------------------------------------------------------------------------