• TypeScript学习 + 贪吃蛇项目


    TypeSCript简介

    1. TypeScript是JavaScript的超集。
    2. 它对JS进行了扩展,向JS中引入了类型的概念,并添加了许多新的特性。
    3. TS代码需要通过编译器编译为JS,然后再交由JS解析器执行。
    4. TS完全兼容JS,换言之,任何的JS代码都可以直接当成TS使用。
    5. 相较于JS而言,TS拥有了静态类型,更加严格的语法,更强大的功能;
    6. TS可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率;
    7. TS代码可以编译为任意版本的JS代码,可有效解决不同JS运行环境的兼容问题;
    8. 同样的功能,TS的代码量要大于JS,但由于TS的代码结构更加清晰,变量类型更加明确,在后期代码的维护中TS却远远胜于JS

    TS环境搭建

    NODEJS安装参照

    全局安装typescript
    npm i typescript -g
    对ts文件进行编译
    tsc ./index.ts
    监听编译文件的变化事实更新
    tsc ./index.ts -w

    基本类型

    类型声明就是为了给变量设置类型,使得变量只能存储某种类型的值

    语法:

    	
    	  let 变量 = 'hello' // TS拥有自动判断类型的机制,该变量此时为string类型
    
          let 变量: 类型;
          
          let 变量: 类型 =;
          
          function fn(参数: 类型, 参数: 类型): 类型{
              ...
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    类型:

    类型例子描述
    number1, -33, 2.5任意数字
    string‘hi’, “hi”, hi任意字符串
    booleantrue、false布尔值true或false
    字面量其本身限制变量的值就是该字面量的值
    any*任意类型
    unknown*类型安全的any
    void空值(undefined)没有值(或undefined)
    never没有值不能是任何值
    object{name:‘孙悟空’}任意的JS对象
    array[1,2,3]任意JS数组
    tuple[4,5]元素,TS新增类型,固定长度数组
    enumenum{A, B}枚举,TS中新增类型

    number

    let a: number = 1
    console.log(a)
    
    function sum(a: number, b: number): number {
        return a + b
    }
    console.log(sum(123, 456))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    字面量

    //使用字面量进行类型声明
    let b: 'male' | 'female'
    b = 'male'
    b = 'female'
    
    let c: number | boolean
    c = 10
    c = false
    c = true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    any

    //any类型 , any类型可以赋值给任意变量
    //第一种声明方式
    let d: any
    d = 'asd'
    d = 111
    //第二种声明方式
    let e
    e = true
    e = 222
    
    c = d
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    unknown

    //unknown类型实际上是一个类型安全的any,不能直接赋值给其他变量
    let f: unknown
    f = 'hello'
    f = 3333
    
    // unknown类型可以进行类型断言
    /*语法:
    *   变量 as 类型
    *   <类型>变量*/
    c = f as number
    c = f
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    void

    //void 返回值为空
    function fun(): void {
    
        return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    never

    //never 表示永远不会有返回结果
    function fun2(): never {
        throw new Error('错误信息')
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    object

    let a: object
    a = {}
    a = function () {
    }
    console.log(a)
    //{}用来指定对象中包含那些属性
    // 语法:{属性名:属性值,属性名:属性值}
    // 属性名后面加上?,表示该属性为可选属性
    let b: { name: string, age?: number }
    b = {name: 'jsl', age: 20}
    console.log(b)
    // [propName: string]: any表示可以添加多个任意类型的属性
    let c: { name: string, [propName: string]: any }
    c = {name: 'jsl', age: 20, gender: '男'}
    console.log(c)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    函数

    //定义函数类型
    /*设置函数结构的类型声明
    *   语法:(参数: 类型, 参数: 类型, ...) => 返回值类型
    * */
    let d: (a: number, b: number) => number
    d = function (a, b): number {
        return a + b
    }
    console.log(d(12, 34))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Array

    /*数组类型的声明
    *   类型[]
    *   Array<类型>
    */
    // string[] 表示一个字符串类型的数组
    let e: string[]
    e = ['1', '23', '445']
    let f: Array
    f = [1, 2, 3, 4]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    元组 tuple

    // 元组:元组是固定长度的数组
    //    语法:[类型, 类型, 类型...]
    let g: [string, number]
    g = ['jsl', 20]
    
    • 1
    • 2
    • 3
    • 4

    枚举 enum

    /*枚举类型*/
    enum Gender {
        male,
        female
    }
    let h: {name: string, gender: Gender}
    h = {name: 'jsl', gender: Gender.male}
    console.log(h.gender === Gender.male)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    类型别名

    // & 表示同时
    let z: {name: string} & {age: number}
    z = {name: 'jsl', age: 20}
    
    // 类型别名
    type myType = 1 | 2 | 3 | 4
    // let x: 1 | 2 | 3 | 4
    let x: myType
    x = 2
    x = 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    编译选项

    • 如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。

    • 但是能直接使用tsc命令的前提是,要先在项目根目录下创建一个ts的配置文件 tsconfig.json

    • tsconfig.json是一个JSON文件,添加配置文件后,只需只需 tsc 命令即可完成对整个项目的编译

    配置选项

    • 配置选项:

      • include

        • 定义希望被编译文件所在的目录

        • 默认值:[ “**/*” ]

        • 示例:

          • "include" : ["src/**/*", "tests/**/*"]
            
            • 1
          • 上述示例中,所有src目录和tests目录下的文件都会被编译

      • exclude

        • 定义需要排除在外的目录

        • 默认值:[“node_modules”, “bower_components”, “jspm_packages”]

        • 示例:

          • "exclude": ["./src/hello/**/*"]
            
            • 1
          • 上述示例中,src下hello目录下的文件都不会被编译

      • extends

        • 定义被继承的配置文件

        • 示例:

          • "extends": "./configs/base"
            
            • 1
          • 上述示例中,当前配置文件中会自动包含config目录下base.json中的所有配置信息

      • files

        • 指定被编译文件的列表,只有需要编译的文件少时才会用到

        • 示例:

          • "files": [
                "core.ts",
                "sys.ts",
                "types.ts",
                "scanner.ts",
                "parser.ts",
                "utilities.ts",
                "binder.ts",
                "checker.ts",
                "tsc.ts"
              ]
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
          • 列表中的文件都会被TS编译器所编译

        • compilerOptions

          • 编译选项是配置文件中非常重要也比较复杂的配置选项

          • 在compilerOptions中包含多个子选项,用来完成对编译的配置

            • 项目选项

              • target

                • 设置ts代码编译的目标版本

                • 可选值:

                  • ES3(默认)、ES5(推荐)、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
                • 示例:

                  • "compilerOptions": {
                        "target": "ES6"
                    }
                    
                    • 1
                    • 2
                    • 3
                  • 如上设置,我们所编写的ts代码将会被编译为ES6版本的js代码

              • lib

                • 指定代码运行时所包含的库(宿主环境)

                • 可选值:

                  • ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost …
                • 示例:

                  • "compilerOptions": {
                        "target": "ES6",
                        "lib": ["ES6", "DOM"],
                        "outDir": "dist",
                        "outFile": "dist/aa.js"
                    }
                    
                    • 1
                    • 2
                    • 3
                    • 4
                    • 5
                    • 6
              • module

                • 设置编译后代码使用的模块化系统

                • 可选值:

                  • CommonJS、UMD、AMD、System、ES2020、ESNext、None
                • 示例:

                  • "compilerOptions": {
                        "module": "CommonJS"
                    }
                    
                    • 1
                    • 2
                    • 3
              • outDir

                • 编译后文件的所在目录

                • 默认情况下,编译后的js文件会和ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置

                • 示例:

                  • "compilerOptions": {
                        "outDir": "dist"
                    }
                    
                    • 1
                    • 2
                    • 3
                  • 设置后编译后的js文件将会生成到dist目录

              • outFile

                • 将所有的文件编译为一个js文件

                • 默认会将所有的编写在全局作用域中的代码合并为一个js文件,如果module制定了None、System或AMD则会将模块一起合并到文件之中

                • 示例:

                  • "compilerOptions": {
                        "outFile": "dist/app.js"
                    }
                    
                    • 1
                    • 2
                    • 3
              • rootDir

                • 指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过rootDir可以手动指定根目录

                • 示例:

                  • "compilerOptions": {
                        "rootDir": "./src"
                    }
                    
                    • 1
                    • 2
                    • 3
              • allowJs

                • 是否对js文件编译
              • checkJs

                • 是否对js文件进行检查

                • 示例:

                  • "compilerOptions": {
                        "allowJs": true,
                        "checkJs": true
                    }
                    
                    • 1
                    • 2
                    • 3
                    • 4
              • removeComments

                • 是否删除注释
                • 默认值:false
              • noEmit

                • 不对代码进行编译
                • 默认值:false
              • sourceMap

                • 是否生成sourceMap
                • 默认值:false
            • 严格检查

              • strict
                • 启用所有的严格检查,默认值为true,设置后相当于开启了所有的严格检查
              • alwaysStrict
                • 总是以严格模式对代码进行编译
              • noImplicitAny
                • 禁止隐式的any类型
              • noImplicitThis
                • 禁止类型不明确的this
              • strictBindCallApply
                • 严格检查bind、call和apply的参数列表
              • strictFunctionTypes
                • 严格检查函数的类型
              • strictNullChecks
                • 严格的空值检查
              • strictPropertyInitialization
                • 严格检查属性是否初始化
            • 额外检查

              • noFallthroughCasesInSwitch
                • 检查switch语句包含正确的break
              • noImplicitReturns
                • 检查函数没有隐式的返回值
              • noUnusedLocals
                • 检查未使用的局部变量
              • noUnusedParameters
                • 检查未使用的参数
            • 高级

              • allowUnreachableCode
                • 检查不可达代码
                • 可选值:
                  • true,忽略不可达代码
                  • false,不可达代码将引起错误
              • noEmitOnError
                • 有错误的情况下不进行编译
                • 默认值:false
    {
        /*
            include: 用来指定那些ts文件需要编译
                路径:     ** 表示任意目录
                        * 表示任意文件
            exclude:不需要被编译的ts文件
                默认值:["node_modules", "bower_components", "jspm_packages"]
        */
        "include": ["./src/*"],
        "exclude": ["node_modules", "bower_components", "jspm_packages"],
        "compilerOptions": {
            // 所有严格检查的总开关
            "strict": true,
            // target:指定ts被编译为哪个ES版本(ES6 推荐)
            "target": "ES6",
            // module:使用哪个模块化标准(ES6 推荐)
            "module": "ES6",
            // lib:指定项目中要使用的库(don't modify generally)
            //"lib": [],
            // outDir:编译后的js文件存放目录(output directory)
            "outDir": "./dist",
            // outFile:将编译后的文件合并为一个文件
            //"outFile": "./dist/main.js"
            // allowJs:是否编译js文件(default false)
            "allowJs": false,
            // checkJs:是否检查js文件符合ts标准(default false)
            "checkJs": false,
            // removeComments:是否移除注释(default false)
            "removeComments": true,
            // noEmit:不生成编译后的文件(默认 false)
    //        "noEmit": false,
            // noEmitOnError:有错误时不生成编译文件
            "noEmitOnError": true,
            // alwaysStrict:使用严格模式(默认 false)
            "alwaysStrict": false,
            // 不允许使用隐式any类型(默认 false)
            "noImplicitAny": false,
            // noImplicitThis:不允许不明确的this(默认 false)
            "noImplicitThis": false,
            // strictNUllChecks:严格检查空值
            "strictNullChecks": false,
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    使用webpack对项目进行打包

    • 通常情况下,实际开发中我们都需要使用构建工具对代码进行打包,TS同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TS。

    • 步骤:

      1. 初始化项目

        • 进入项目根目录,执行命令 npm init -y
          • 主要作用:创建package.json文件
      2. 下载构建工具

        • npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader html-webpack-plugin
          • 共安装了6个包
            • webpack
              • 构建工具webpack
            • webpack-cli
              • webpack的命令行工具
            • webpack-dev-server
              • webpack的开发服务器
            • typescript
              • ts编译器
            • ts-loader
              • ts加载器,用于在webpack中编译ts文件
            • html-webpack-plugin
              • webpack中html插件,用来自动创建html文件

    开发中还经常需要结合babel来对代码进行转换以使其可以兼容到更多的浏览器,在上述步骤的基础上,通过以下步骤再将babel引入到项目中。
    安装依赖包:
    - npm i -D @babel/core @babel/preset-env babel-loader core-js
    - 共安装了4个包,分别是:
    - @babel/core
    - babel的核心工具
    - @babel/preset-env
    - babel的预定义环境
    - @babel-loader
    - babel在webpack中的加载器
    - core-js
    - core-js用来使老版本的浏览器支持新版ES语法

    • 这样,使用ts编译后的文件将会再次被babel处理,使得代码可以在大部分浏览器中直接使用,可以在配置选项的targets中指定要兼容的浏览器版本。
    1. 根目录下创建webpack的配置文件webpack.config.js
    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/main.ts',
        output: {
            path: path.join(__dirname, 'dist'),
            filename: '[name].bundle.js',
            clean: true,
        },
        module: {
            rules: [
                {
                    test: /\.ts$/,
                    use: [
                        {
                            loader: "babel-loader",
                            options:{
                                presets: [
                                    [
                                        "@babel/preset-env",
                                        {
                                            "targets":{
                                                "chrome": "58",
                                                "ie": "11"
                                            },
                                            "corejs":"3",
                                            "useBuiltIns": "usage"
                                        }
                                    ]
                                ]
                            }
                        },
                        {
                            loader: "ts-loader",
    
                        }
                    ],
                    // use: 'ts-loader',
                    exclude: /node_modules/
                }
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                title: '自定义的title',
                template: './public/index.html',
                filename: 'index.html'
            })
        ],
        devServer: {
            open: true,
            port: 8899
        },
        // 用来设置引用模块
        resolve: {
            extensions: ['.ts', '.js']
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    1. 根目录下创建tsconfig.json,配置可以根据自己需要

      • {
            "compilerOptions": {
                "target": "ES2015",
                "module": "ES2015",
                "strict": true
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
    2. 修改package.json添加如下配置

         {
           ......
      "scripts": {
          "dev": "webpack serve --mode=development",
          "build": "webpack"
        },
           ......
         }
         ```
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    3. 在src下创建ts文件,并在并命令行执行npm run build对代码进行编译,或者执行npm run dev来启动开发服务器

    面向对象

    • 操作浏览器要使用window对象
    • 操作网页要使用document对象
    • 操作控制台要使用console对象

    定义类
    class Person {
        // 静态属性
        static str: string = 'jsl'
        // 只读属性,不可修改
        readonly age: number = 20
    
        say(): string {
            return '你好,同学'
        }
    }
    
    console.log(new Person().say());
    console.log(Person.str)  // 使用类名.静态属性的方式读取静态属性
    console.log(new Person().age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    构造器和继承(extends)
    • 通过继承可以将其他类中的属性和方法引入到当前类中

    • 重写

      • 发生继承时,如果子类中的方法会替换掉父类中的同名方法,这就称为方法的重写
    
    
    class Animal {
        name: string;
        age: number;
    
        constructor(name: string, age: number) {
            this.name = name
            this.age = age
        }
    
        say() {
            console.log(this.name + ' Animal类 说 你好')
        }
    }
    
    class Dog extends Animal {
        type: string;
    
        constructor(name: string, age: number, type: string) {
            super(name, age);
            this.type = type
        }
    
        sayWang() {
            //调用父类的方法
            super.say()
            console.log(this.name + '  ' + this.type + '  ' + '汪汪~')
        }
    
        run(num:number) {
            console.log(this.name + ' run ' + num + '米')
        }
    }
    
    class Cat extends Animal {
        constructor(name: string, age: number) {
            super(name, age);
        }
    
        sayMiao() {
            //调用父类的方法
            super.say()
            console.log(this.name + '  ' + this.age + '  ' + '喵喵~')
        }
    
        sayhello = super.say
    }
    
    const dog: Dog = new Dog('可乐', 4, `田园犬`)
    dog.sayWang()
    dog.run(100)
    
    new Dog('糖果', 1, 'chaiquan').sayWang()
    new Cat('火龙果', 2).sayhello()
    new Cat('芒果', 7).sayMiao()
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    抽象类
    • 抽象类(abstract class)

      • 抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例
    abstract class Animal {
        name: string;
        age: number;
    
        protected constructor(name: string, age: number) {
            this.name = name
            this.age = age
        }
    
        // 定义一个抽象方法,让子类去实现具体的代码
        // 只能定义在抽象类中,子类必须对抽象方法进行重写
        abstract say(): void
    }
    
    class Dog extends Animal {
        type: string;
    
        constructor(name: string, age: number, type: string) {
            super(name, age);
            this.type = type
        }
    
        //实现父类的抽象方法
        say() {
            console.log('Dog类 :' + this.name + '  ' + this.age + '岁了')
        }
    
        /*run(num: number) {
            console.log(this.name + ' run ' + num + '米')
        }*/
    }
    
    class Cat extends Animal {
        constructor(name: string, age: number) {
            super(name, age);
        }
    
        //实现父类的抽象方法
        say() {
            console.log('Cat类 ' + this.name)
        }
    }
    
    new Dog('狗胜', 4, '田园').say()
    new Cat('芒果', 2).say()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    接口 interface

    接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。

    // 描述一个对象的类型
    type objType = {
        name: string,
        age: number,
        gender: number,
    }
    
    const obj: objType = {
        name: 'jsl',
        age: 20,
        gender: 1
    }
    
    console.log(obj)
    
    //定义一个接口
    //定义接口就是定义一套规范,所有的属性 方法 都没有实际的值
    //接口中的方法都是抽象方法,抽象类里面可有有抽象方法也可以有普通方法
    //接口用来实现,抽象类用来继承
    interface objInterface {
        name: string
        age: number
        address: string
    
        run(): void
    
        eat(): void
    }
    
    
    const person: objInterface = {
        name: 'hello',
        age: 18,
        address: '郑州',
        eat() {
            console.log('吃饭')
        },
        run() {
            console.log('跑步')
        }
    }
    console.log(person)
    
    //类实现接口,该类就要满足接口的规范,是一种标准
    class myInterface implements objInterface {
        address: string;
        age: number;
        name: string;
    
        constructor(name: string, age: number, address: string) {
            this.name = name
            this.age = age
            this.address = address
        }
    
        eat(): void {
            console.log('myInterface 实现objInterface接口 实现eat方法')
        }
    
        run(): void {
            console.log('myInterface 实现objInterface接口 实现run方法')
        }
    
    }
    let i = new myInterface('打嗝', 2, 'zhegnzhou')
    i.eat()
    console.log(i.name = '可乐');
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    泛型(Generic)

    定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。

    /*泛型*/
    
    //定义一个泛型函数
    /*
    函数有一个参数类型不确定,但是能确定的时其返回值的类型和参数的类型是相同的,由于类型不确定所以参数和返回值均使用了any,但是很明显这样做是不合适的,首先使用any会关闭TS的类型检查,其次这样设置也不能体现出参数和返回值是相同的类型,这里就用到了泛型
    */
    
    function fun<K> (a: K): K {
        return a
    }
    /*这里的``````就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在函数中使用T来表示该类型。所以泛型其实很好理解,就表示某个类型。
    */
    fun(123) // 不指定泛型,TS可以自动对类型进行推断
    
    console.log(fun<string>('hello')); // 指定泛型
    
    //接口泛型
    interface Inter {
        name: string
        age: number
        length: number
    }
    class In implements Inter {
        name: string = 'jsl'
        age: number = 20
        length: number = 100
    
    }
    /*使用T extends MyInter表示泛型T必须是MyInter的子类,不一定非要使用接口类和抽象类同样适用。
    */
    function fun2<K extends Inter> (a: K): number {
        return a.length
    }
    
    console.log(fun2(new In()));
    
    // 类 泛型
    class MyClass<K extends Inter> {
        name: K
        constructor(name: K) {
            this.name = name
        }
    
        toString() {
            console.log(this.name)
        }
    }
    new MyClass(new In()).toString()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    面向对象的特点

    • 封装

      • 对象实质上就是属性和方法的容器,它的主要作用就是存储属性和方法,这就是所谓的封装

      • 默认情况下,对象的属性是可以任意的修改的,为了确保数据的安全性,在TS中可以对属性的权限进行设置

      • 只读属性(readonly):

        • 如果在声明属性时添加一个readonly,则属性便成了只读属性无法修改
      • TS中属性具有三种修饰符:

        • public(默认值),可以在类、子类和对象中修改
        • protected ,可以在类、子类中修改
        • private ,可以在类中修改
    • 属性存取器

      • 对于一些不希望被任意修改的属性,可以将其设置为private

      • 直接将其设置为private将导致无法再通过对象修改其中的属性

      • 我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器

      • 读取属性的方法叫做setter方法,设置属性的方法叫做getter方法

    /*对类 私有属性封装 设置set get 方法
    * public(默认) 修饰的属性可以在任意位置访问、修改
    * protected:受保护的,修饰的属性可以在自身的类和子类中访问 修改
    * private:私有的,修饰的属性只能在自身类 中访问 修改
    * */
    
    class Person {
        private name: string
        private age: number
    
        constructor(name: string, age: number) {
            this.name = name
            this.age = age
        }
    
        /*想想java就明白了 get  set 方法*/
    
        /*setName(name: string): void {
            this.name = name
        }
    
        getName(): string {
            return this.name
        }
    
        //可以进行传值判断
        setAge(age: number): void {
            if (age >= 0 && age <= 130)
                this.age = age
        }
    
        getAge(): number {
            return this.age
        }*/
    
        set name(name: string) {
            this.name = name
        }
    
        get name(): string {
            return this.name
        }
    
        set age(age: number) {
            if (age >= 0 && age <= 130)
                this.age = age
        }
    
        get age(): number {
            return this.age
        }
    
        toString() {
            console.log(this.name + '  ' + this.age)
        }
    }
    
    const p = new Person('jsl', 20)
    p.setName('hello')
    console.log(p.getName())
    p.setAge(90)
    console.log(p.getAge())
    p.toString()
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    贪吃蛇模块

    页面实现一个简单地贪吃蛇游戏
    贪吃蛇
    使用上下方向键控制移动
    使用webpack搭建开发环境;
    这里的一些配置环境直接粘贴就好,重点是几个业务类的开发和蛇的移动逻辑开发
    涉及到的开发依赖:

    	"scripts": {
    	        "dev": "webpack serve --mode=development",
    	        "build": "webpack --mode=production"
    	    },
        "devDependencies": {
            "@babel/core": "^7.22.11",
            "@babel/preset-env": "^7.22.14",
            "babel-loader": "^9.1.3",
            "core-js": "^3.32.1",
            "css-loader": "^6.8.1",
            "html-webpack-plugin": "^5.5.3",
            "less": "^4.2.0",
            "less-loader": "^11.1.3",
            "postcss": "^8.4.29",
            "postcss-loader": "^7.3.3",
            "postcss-preset-env": "^9.1.2",
            "style-loader": "^3.3.3",
            "ts-loader": "^9.4.4",
            "typescript": "^5.2.2",
            "webpack": "^5.88.2",
            "webpack-cli": "^5.1.4",
            "webpack-dev-server": "^4.15.1"
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    系统文件架构

    --public
    	--index.html
    --src
    	--assets
    	--style
    		--index.less
    	--ts
    		--food.ts
    		--gameControl.ts
    		--scorePanel.ts
    		--snake.ts
    	--index.ts
    --package.json
    --tsconfig.json
    --webpack.config.js
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    tsconfig.json

    {
        "include": ["./src/**/*"],
        "compilerOptions": {
            "target": "ES6",
            "module": "ES6",
            "strict": true,
    //        "noEmitOnError": true
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    webpack.config.js

    const path = require('path')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/index.ts',
        output: {
            filename: '[name].bundle.js',
            path: path.join(__dirname, 'dist'),
            clean: true
        },
        module: {
            rules: [
                {
                    test: /\.ts$/,
                    use: [
                        {
                            loader: "babel-loader",
                            options:{
                                presets: [
                                    [
                                        "@babel/preset-env",
                                        {
                                            "targets":{
                                                "chrome": "58",
                                                "ie": "11"
                                            },
                                            "corejs":"3",
                                            "useBuiltIns": "usage"
                                        }
                                    ]
                                ]
                            }
                        },
                        {
                            loader: "ts-loader",
    
                        }
                    ],
                    // use: 'ts-loader',
                    exclude: /node_modules/
                },
                {
                    test: /\.less$/,
                    use: [
                        'style-loader',
                        'css-loader',
                        {
                            loader: 'postcss-loader',
                            options: {
                                postcssOptions: {
                                    presets: [
                                        "postcss-preset-env",
                                        {
                                            browsers: "last 2 versions"
                                        }
                                    ]
                                }
                            }
                        },
                        'less-loader'
                    ]
                }
            ]
        },
        plugins: [
            new htmlWebpackPlugin({
                //没有html文件时生效,创建了html文件后该属性失效
                title: 'hello',
                template: './public/index.html',
                filename: 'index.html'
            })
        ],
        devServer: {
            open: true,
            port: 8890
        },
        resolve: {
            extensions: ['.ts', '.js']
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    在VMware上创建虚拟机并安装CentOS
    音视频专题--opengl (3)
    【软考软件评测师】2020综合知识历年真题
    B-000 硬件工程师手册
    Markdown
    Redis_哨兵模式
    苹果录音删除了可以恢复吗?请收藏好这些方法!
    Java虚拟机(JVM)面试题(总结最全面的面试题!!!)
    ✔ ★【备战实习(面经+项目+算法)】 10.16学习时间表(总计学习时间:5h)
    AI人工智能简史
  • 原文地址:https://blog.csdn.net/NOfighting/article/details/132627638