文章内容输出来源:拉勾教育 大前端高薪训练营

前言

在 【浅谈 TypeScript【上】】中,简单讲述了关于JavaScript静态类型检查工具Flow的用法等。可以看到,我们接下来讲述的TypeScript与它其实有很多相似之处。

TS 与 JS

TypeScript 并不是一个完全新的语言, 它是 JavaScript 的超集,为 JavaScript 的生态增加了类型机制,并最终将代码编译为纯粹的 JavaScript 代码。

TypeScript JavaScript
JavaScript 的超集用于解决大型项目的代码复杂性 一种脚本语言,用于创建动态网页。
可以在编译期间发现并纠正错误 作为一种解释型语言,只能在运行时发现错误
强类型,支持静态和动态类型 弱类型,没有静态类型选项
最终被编译成 JavaScript 代码,使浏览器可以理解 可以直接在浏览器中使用
支持模块、泛型和接口 不支持模块,泛型或接口
支持 ES3,ES4,ES5 和 ES6 等 不支持编译其他 ES3,ES4,ES5 或 ES6 功能
社区的支持仍在增长,而且还不是很大 大量的社区支持以及大量文档和解决问题的支持

TypeScript 概述

首先,我们先来看一下 TypeScript的范围图:

TypeScript 是由微软开发的一种开源、跨平台的编程语言,是JavaScript 的超集,主要提供了类型系统和对 ES6 的支持,最终会被编译为JavaScript代码。可以说,TypeScript是前端领域中的第二语言,属于渐进式语言。

一、定义

引用官网定义:

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open source.

中文意思:

TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。TypeScript 编译工具可以运行在任何服务器和任何系统上。TypeScript 是开源的。

二、特点

  1. 自动转换新特性,最低可以编译到ES3版本;
  2. 任何一种 JavaScript 运行环境都支持;
  3. 相比于Flow,功能更为强大,生态也更健全、更完善。

三、TypeScript的优势和缺点

TypeScript的优势

  1. TypeScript 增加了代码的可读性和可维护性
    a. 类型系统可以方便用户快速的使用类型定义过后的函数变量;
    b. 在编译阶段发现错误,节省了运行之后出错的维护时间;
    c. 增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等。

  2. TypeScript 非常包容
    a. TypeScript 是 JavaScript 的超集,.js 文件可以直接重命名为 .ts 即可;
    b. 可以根据变量的值等进行类型推论,可以定义从简单到复杂的几乎一切类型;
    c. TypeScript 编译报错,不会影响生成 JavaScript 文件;
    d. 兼容第三方库,即使第三方库不是用 TypeScript 写的,也可以编写单独的类型文件供 TypeScript 读取。

  3. TypeScript 拥有活跃的社区
    a. 大部分第三方库都有提供给 TypeScript 的类型定义文件;
    b. Google 开发的 Angular2 就是使用 TypeScript 编写的;
    c. TypeScript 拥抱了 ES6 规范,也支持部分 ESNext 草案的规范。

TypeScript的缺点

  1. TypeScript 增加了接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师不熟悉的概念,需要一定的学习成本;
  2. 项目初期,TypeScript 会增加一些开发成本,需要去编写一些类型的定义。但在后期维护时,会减少维护成本。
  3. 集成到构建流程需要一些工作量;
  4. 可能和一些库结合的不是很完美。

快速上手

  • 以下操作需在 cmd 命令行界面进行,并使用 yarn (或 npm/cnpm)执行安装运行命令。
  1. 初始化包管理文件 package.json

    yarn init --yes  // --yes 表示快速初始化
    
  2. 安装 TypeScript
    yarn add typescript --dev   // --dev 表示项目内安装,而非全局安装
    
  3. 新建 .ts 结尾的 hello.ts文件,使用 tsc 命令将 .ts文件编译为 .js文件
    yarn tsc hello.ts    // 进入到当前目录,否则需加上文件路径
    
  • 解析

    编译过程中,先检查类型是否使用异常,然后移除一些类型注解等扩展语法,并且会自动转换 ECMAScript 的新特性。

配置文件

  • 在项目根目录进行操作, tsconfig.json 配置属性将简单介绍。
  1. 初始化 tsconfig.json 配置文件

    yarn tsc --init
    
  2. tsconfig.json 配置属性

    {"compilerOptions": {  "target": "es5",          /* Specify ECMAScript target version */"module": "commonjs",     /* Specify module code generation */"sourceMap": true, /* Generates corresponding '.map' file. */"outDir": "dist",  /* Redirect output structure to the directory. */                "rootDir": "src",  /* Specify the root directory of input files. */             "strict": true,    /* Enable all strict type-checking options. */                     "esModuleInterop": true,            "skipLibCheck": true,                   "forceConsistentCasingInFileNames": true  }
    }
    

    – rootDir:编译源代码,一般在 src 文件夹中存放
    – outDir:输出文件,一般放置在 dist 文件夹中

  3. 根据配置文件,编译 src 中全部的 .ts 文件

    yarn tsc
    

基础语法

原始数据类型

在JavaScript中,原始数据类型分别为:数值类型、字符串类型、布尔类型、Null、Undefined以及ES6中新增的Symbol。

字符串类型

使用 string 定义字符串类型:

const a: string = 'foobar'

编译结果:

"use strict";        // 配置文件中,配置了严格模式为 true
var a = 'foobar';

数值类型

使用 number 定义数值类型:

const num: number = 100
const na: number = NaN
const infi: number = Infinity

编译结果:

var num = 100;
var na = NaN;
var infi = Infinity;

布尔类型

使用 boolean 定义布尔值类型:

const t: boolean = true
const f: boolean = false

编译结果:

var t = true;
var f = false;

空值

JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数:

function voidTest(): void {// 函数体
}

声明变量的数据类型为 void 时,非严格模式下,变量的值可以为 undefined 或 null。而严格模式下,变量的值只能为 undefined。

const u: void = undefined
const t: void = null   // 严格模式下,语法报错

Null 与 Undefined

使用 nullundefined 来定义 null 和 undefined 这两个原始数据类型:

const f: null = null
const g: undefined = undefined

编译结果:

var f = null;
var g = undefined;

注意

void类型的变量不能赋值给 number 、string、boolean类型的变量。

let u: void;
let num1: number = u;
// Type 'void' is not assignable to type 'number'.

严格模式下,null、undefined类型的变量不能赋值给 number 、string、boolean类型的变量。

let num2: number = undefined;
// Type 'undefined' is not assignable to type 'number'.let num3: number = null;
// Type 'null' is not assignable to type 'number'.

Symbol

Symbol 是ES2015中新增的数据类型。因此,我们需要做一些操作,使程序在编译过程中可以识别 ES2015中的新特性。

解决方案

  • 方案一:
    将 tsconfig.json 文件中的 “target”,设为 “es2015” 以上版本。

  • 方案二:
    tsconfig.json 文件中的 “target” 还是为 “es5"等原来的版本,但要添加标准库(标准库就是内置对象所对应的声明),即在 tsconfig.json 文件中的 “lib” 数组中添加 “ES2015”,但是若只添加这一选项,则会覆盖原来的标准库,因此需要把原来的标准库添加回来,如"DOM”(在标准库中,"DOM"标准库包含了 dom 和bom)

const h: symbol = Symbol()

Object 类型

  • 不是特指对象类型,而是泛指所有的非原始的数据类型,即包括 对象、数组、函数 等。
const foo: object = function () {}
const bar: object = []
const baz: object = {}// 类似对象字面量:属性类型数量要一一对应
const obj: { foo: number, bar: string } =  { foo: 123, bar: 'string' }

数组类型

声明数组的两种形式:

  • 使用 Array泛型
const arr1: Array<number> = [1, 2, 3]
  • 使用 数据类型 + [] 形式,这种比较常用
const arr2: number[] = [1, 2, 3] // 数据类型 + [], 常用的举例
function sum (...args: number[]) {return args.reduce((prev, current) => prev + current, 0)
}
// sum(1, 2, 3, 'foo') // 报错

元组类型(Tuple Types)

元组就是一个明确元素数量以及元素类型的数组。各个元素的类型不必要完全相同。一般用于在一个函数中去返回多个返回值。

定义元组

  • 使用类似 数组字面量 的形式,如果元素对应类型不相符,或者元素数量不一致,都会报错。
const tuple: [number, string] = [18, 'foo']

访问的两种形式

  • 使用数组下标的形式
const age = tuple[0]
const name = tuple[1]
  • 使用数组解构的方式,提取数组中的每个元素
const [age, name] = tuple// 返回元组的例子
Object.entries({foo: 123,bar: 456
})

枚举类型

特点
1、给一组数值去分别取上一个更好理解的名字;
2、一个枚举中只会存在几个固定的值,并不会出现超出范围的可能性。

语法和注意

  • js语法:使用对象模拟实现枚举
const PostStatus = {Draft: 0,Unpublished: 1,Published: 2
}
  • TypeScript语法:使用 enum 关键字, 注意使用的是 “=”
const PostStatus = {Draft = 0,Unpublished = 1,Published = 2
}
  • 可以不指定具体的值,默认从 0 开始累加
enum PostStatus {Draft,Unpublished,Published
}
  • 也可以给第一个指定具体的值,后面的值将会在第一个指定值的基础上,执行累加
enum PostStatus {Draft = 3,Unpublished,Published
}
  • 给定的值,既可以是数值型,也可以是字符串,即字符串枚举
// 由于字符串无法累加,因此需要自行赋值。字符串枚举并不常见
enum PostStatus {Draft = 'aaa',Unpublished = 'bbb',Published = 'ccc'
}
// PostStatus[0] // =>Draft 通过索引器的形式访问对应的枚举名称

枚举类型会影响编译的结果,最终会编译为双向的键值对对象。
编译结果:

 // 目的:可以让我们动态的通过枚举值(0, 1, 2, ...)去获取枚举的名称
var PostStatus;
(function (PostStatus) {PostStatus["Draft"] = "aaa";PostStatus["Unpublished"] = "bbb";PostStatus["Published"] = "ccc";
})(PostStatus || (PostStatus = {}));
  • 如果确定不会使用索引器的形式访问枚举,那么建议使用常量枚举。
const enum PostStatus {Draft,Unpublished,Published
}
const post = {title: 'Hello TypeScript',content: 'TypeScript is a typed superset of JavaScript.',status: PostStatus.Draft // 2 // 1 // 0
}

函数类型

对函数的输入输出进行类型限制,输入:参数;输出:返回值。

定义函数的方式

  • 方式一:函数声明
/**  * 如果某个参数可传可不传:*    1、可在形参的参数名后面添加 "?" , 使其变成可选的;*    2、使用 es6中添加参数默认值的方法, 使其变成可有可无的。* * 若需要接收任意个数的参数,使用 es6 中的rest操作符* */function func1 (a: number, b?: number, c: number = 10, ...rest: number[]): string {return 'func1'
}func1(100, 200)

注意
1)形参列表都为必传参数时,传入的实参类型和数量,都必须与形参保持一致;
2)可选参数,必须放在参数列表的最后面。

  • 方式二:函数表达式
    这种对于回调函数的形参类型,需要进行约束。
const fun2: (a: number, b: number) => string = function (a: number, b: number): string {return 'func2'
}

任意类型

any 就是用来接收任意类型数据的一种类型,属于动态类型,不会有任何的类型检查,很可能会存在类型安全的问题,轻易不要使用。

function stringify (value: any) {return JSON.stringify(value)
}stringify('string')
stringify(100)
stringify(true)let foo: any = 'string'
foo = 100 // 在使用过程中,可以接收任意类型的数据foo.bar() // 语法上不会报错

类型断言

类型断言是在编译过程中的概念,代码编译过后,将不会存在。而类型转换是代码运行时的概念。

// 假设这个 nums 来自一个明确的接口
const nums = [110, 120, 119, 112]
const res = nums.find(i => i > 0)// TypeScript 推断出 res: number | undefined,不能执行下面类似操作
const square = res * res    // 报错,不可以执行

类型断言的两种方式

  • 使用 as 关键字,明确告诉 TypeScript 这个数据的具体类型
const num1 = res as number
  • 使用 <数据类型> 的方式,但 JSX下会有语法冲突,不能使用
const num2 = <number>res

接口(Interfaces)

什么是接口

在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。

作用
接口就是用来约束对象的结构。一个对象要是去实现一个接口,那么这个对象必须拥有接口中的所有成员。

语法

interface  接口名称 {属性名1: 数据类型;属性名2: 数据类型...属性名n: 数据类型
}

代码示例如下:

// 约定一个对象当中,具体应该有哪些成员,以及成员的类型又是什么样的interface Post {title: string;           // 内部成员可用 ";" 分割,也可以不加 content: stringsubtitle?: string        // ? 可选成员readonly summary: string // 只读成员}function pointPost (post: Post) {console.log(post.title);console.log(post.content);   }const post: Post = {title: 'Hello TypeScript',content: 'A javascript superset',summary: 'A javascript'
}
// post.summary = 'other' // 不可修改
pointPost(post)// 添加动态成员
interface Cache {[key: string]: string  // key 代表属性名,可随意取名
}const cache: Cache = {}cache.foo = 'value1'
cache.bar = 'value2'

总结
TypeScript 中的接口只是用来为有结构的数据,做类型约束。在实际运行中,没有实际意义。

类(class)

概述
描述一类具体事物的抽象特征,主要用来描述一类具体对象的抽象成员。

声明属性
在TypeScript中要明确,在类型当中声明它所拥有的一些属性,而不是在构造函数当中动态通过this去添加。

/*** ES2016新增,在类型当中声明属性的方式,就是直接在类中定义** 注意:在TypeScript中,类的属性必须有一个初始值* * 属性赋初始值的方式:*    1、在 "=" 后面赋值*    2、在构造函数中进行初始化,动态的为属性赋值*/
class Person {name: string    // = 'init name' age: number constructor (name: string, age: number) {this.name = namethis.age = age}sayHi (msg: string): void {console.log(`I am ${this.name}, ${msg}`)        }
}

类的访问修饰符

  • 作用:
    主要用来控制类当中成员的可访问级别。
  • 分类
    1)private :私有成员,只能在类的内部进行使用,外部访问不到,不允许继承。
    2)public : 公有成员,默认就是 public,建议手动添加上,便于理解。
    3)protected : 受保护的,外部访问不到,只允许在子类当中访问对应的成员,允许继承。
  class Person {public name: string // 公有属性private age: number  // 私有属性protected gender: boolean // 受保护的,只能在子类中被访问constructor (name: string, age: number) {this.name = namethis.age = agethis.gender = true}sayHi (msg: string): void {console.log(`I am ${this.name}, ${msg}`)        console.log(this.age)        }}const tom = new Person('tom', 18)console.log(tom.name)// console.log(tom.age)    // 私有属性,外部访问不到,报错// console.log(tom.gender) // 受保护的属性,只能在子类中访问,报错

构造函数被私有化时,则会发生以下问题:

1)构造函数被私有化,将不能在外部使用 new 关键字进行实例化;
2)需要在类中定义静态方法,并返回 创建的类的实例。

 class Student extends Person {private constructor (name: string, age: number) {super(name, age)console.log(this.gender);}static create (name: string, age: number) {return new Student(name, age)}}const jack = Student.create('jack', 20)

类的只读属性

class Person {protected readonly gender: boolean // readonly 要放在访问修饰符的后面constructor () {this.gender = true             // 注意:初始化过后,不可以再修改}
}

类 与 接口

// 一个接口只去约束一个能力,让一个类型同时去实现多个接口
interface Eat {eat (food: string): void
}
interface Run {run (distance: number): void
}// 不同的类型,实现相同的接口
class Person implements Eat, Run {eat (food: string): void {console.log(`优雅的进餐:${food}`)        }run (distance: number) {console.log(`直立行走:${distance}`)}
}class Animal implements Eat, Run {eat (food: string): void {console.log(`呼噜呼噜的吃:${food}`);        }run (distance: number) {console.log(`爬行:${distance}`)        }
}

抽象类

类似于接口,用来约束子类当中必须要有某一个成员。但与接口不同的是,抽象类可以包含一些具体的实现,而接口只能是某一个成员的抽象,不包括具有的实现。

// 抽象类只能被继承,不能再使用 new 进行实例化
abstract class Animal {eat (food: string): void {console.log(`呼噜呼噜的吃:${food}`)        }// 抽象方法, 不需要方法体abstract run (distance: number): void
}// 当父类中存在抽象方法时,子类必须去实现抽象方法
class Dog extends Animal {run(distance: number): void {console.log('四脚爬行', distance);}}// 子类创建实例时,会同时拥有父类中的方法,以及自身所实现的方法
const d = new Dog()
d.eat('嗯')
d.run(1)

泛型

概述
泛型就是在声明函数时不去指定具体的类型,等到在调用的时候再去传递具体的类型。

目的
极大程度的去复用代码。

function createNumberArray (length: number, value: number): number[] {// Array 默认创建的是 any类型的数组,因此需要使用泛型进行指定,传递一个类型return Array<number>(length).fill(value)
}function createStringArray (length: number, value: string): string[] {return Array<string>(length).fill(value)
}// 不明确的类型,使用 T 替换,调用时传入
function createArray<T> (length: number, value: T): T[] {return Array<T>(length).fill(value)
}// const res = createNumberArray(3, 100) // res => [100, 100, 100]const res = createArray<string>(3, 'foo')

总结
泛型就是定义时不能明确的类型变成一个参数,让我们在使用的时候再去传递的类型参数。

类型声明

作用
兼容普通的js代码。

下面以 lodash 为例,手动声明函数类型

// 此时,只是安装了 'lodash' 开发依赖
import { camelCase } from 'lodash'// 需要使用 declare 关键字,手动声明函数类型
declare function camelCase(input: string): stringconst res = camelCase('hello typed') // 不手动声明,会报错
  • 安装类型声明模块
yarn add @types/lodash --dev

代码如下(示例):

import { camelCase } from 'lodash'const res = camelCase('hello typed')

类型声明模块介绍
类型声明模块没有实际的代码,只是对对应的模块做一些类型声明。若模块中已经存在类型声明,则不需要引入类型声明模块。

@types/模块名   // 形式

作用域问题

在其他文件中,变量或函数等已经在 全局作用域 中定义,再进行定义的话,就会产生命名冲突,编译时会报错。

解决方案

  • 使用 匿名函数,立即执行,生成单独的作用域
(function () {const a = 123
})()
  • 使用 export {},利用导出模块的概念,生成作用域
// 下面的 {} 并不是指导出空对象,而是 export 的语法
// 利用下面的语法,可以使这个文件中的成员变成这个模块当中的局部成员
// 一般不会用,实际开发中,就会以模块的形式进行开发
export {}const a = 123

Polyfill

TS 对于语言的编译,只是语法层面,如果是 API 层面的的补充,需要手动 Polyfill!

core-js

core-js 基本上把能 polyfill API 都实现了。但是,属于手动引入 Polyfill。

  • 1,安装插件模块

      $ npm i core-js --save
    
  • 2,使用core-js,两种引入方式,建议按需引入

    引入语法如下:

      // 一, 全部引入import 'core-js'// 二, 按需引入import 'core-js/features/object'
    
  • 3,测试是否成功

      $ nvm use 12  # 12 node version, compile ts$ tsc         # compile ts$ nvm use 0   # 0 node version$ node xxx.ts # success or failure
    
  • 无法实现 Polyfill

    Object.defineProperty 完全无法 Polyfill
    Promise 微任务,用宏任务代替

Babel

使用 Babel 自动化的 Polyfill。

  • 1,安装依赖模块

      $ npm i @babel/cli @babel/core @babel/preset-env @babel/preset-typescript --save
    

    模块注释

    @babel/cli:babel 的命令行入口
    @babel/core:babel的核心模块
    @babel/preset-env:是一个包含ES新特性所有转换插件的集合,可以根据环境判断哪些转哪些不转
    @babel/preset-typescript:是一个包含typescript转换为ES的插件集合

  • 2,配置babel.config.js文件

    配置代码如下:

      // JSDoc// @ts-check/** @type {import('@babel/core').ConfigAPI} */module.exports = {presets: [['@babel/env',{useBuiltIns: 'usage',corejs: {version: 3}}],'@babel/typescript' // 不会做 TS 语法检查,只是移除类型注解]}
    
  • 3,使用编译命令

      $ npx babel source.ts -o output.js # source.ts 源文件  output.js 编译后的文件
    

浅谈 TypeScript【下】-- TypeScript 语言规范与基本应用相关推荐

  1. python中文字符串编码_浅谈python下含中文字符串正则表达式的编码问题

    前言 Python文件默认的编码格式是ascii ,无法识别汉字,因为ascii码中没有中文. 所以py文件中要写中文字符时,一般在开头加 # -*- coding: utf-8 -*- 或者 #co ...

  2. 浅谈 JavaScript 编程语言的编码规范

    转自:http://www.ibm.com/developerworks/cn/web/1008_wangdd_jscodingrule/?ca=drs-tp4608 developerWorks 中 ...

  3. shell for循环1到100_浅谈Linux下shell 编程的for循环常用的6种结构

    浅谈Linux下shell 编程的for循环常用的6种结构 1. 常用for循环结构 (1) for 变量 in 值1 值2 值3... do 程序块儿 done (2) for 变量 in `命令` ...

  4. Linux系统常用函数,浅谈linux下的一些常用函数的总结(必看篇)

    1.exit()函数 exit(int n)  其实就是直接退出程序, 因为默认的标准程序入口为int main(int argc, char** argv),返回值是int型的. 一般在shell下 ...

  5. python打开文件夹中的tiff_浅谈python下tiff图像的读取和保存方法

    对比测试 scipy.misc和 PIL.Image和 libtiff.TIFF三个库 输入: 1. (读取矩阵) 读入uint8.uint16.float32的lena.tif 2. (生成矩阵) ...

  6. Linux命令删除find,浅谈Linux下通过find命令进行rm文件删除的小技巧

    我们经常会通过find命令进行批量操作,如:批量删除旧文件.批量修改.基于时间的文件统计.基于文件大小的文件统计等,在这些操作当中,由于rm删除操作会导致目录结构变化,如果要通过find结合rm的操作 ...

  7. 对计算机辅助英语的看法,浅谈利用计算机辅助英语语言测试

    摘要:随着计算机技术不断深入发展,给我们的生活和学习带来了翻天覆地的变化,越来越多的学校利用计算机辅助各学科进行教学,对计算机教学设施的配备与老师掌握计算机技术方法的要求越来越高.尤其是利用计算机进行 ...

  8. c语言在数学方面的应用编程,浅谈数学在C语言编程中的应用.doc

    浅谈数学在C语言编程中的应用 浅谈数学在C语言编程中的应用 [][]C语言对学习者的数学基础要求较高对一部分学生来说学好C语言有一定的困难.本文就本专业知识和自身对C语言的学习经验对数学在C语言编程中 ...

  9. 计算机病毒的隐藏方式有ign,浅谈windows下的病毒隐藏技术.doc

    浅谈windows下的病毒隐藏技术 浙江工业职业技术学院 毕业论文 (2011届) 浅谈windows下的病毒隐藏技术 学生姓名 学 号 分 院 专 业 信 指导教师 完成日期 2011年5月 19日 ...

  10. linux cp mv区别,浅谈Linux下mv和cp命令的区别

    1.功能上的区别 mv:用户可以使用该命令为文件或目录重命名或将文件由一个目录移入另一个目录中. cp: 该命令的功能是将给出的文件或目录拷贝到另一文件或目录中. 2.从inode角度来区分 mv:会 ...

最新文章

  1. UiPath Level 1-Lesson 2. Variables Data Types Introduction
  2. 学生管理系统代码赏析
  3. Git + GitHub 超详细知识笔记整理
  4. IM即时通讯结合mui 环信
  5. Javascript深入理解构造函数和原型对象
  6. Linux查看机器的硬件信息
  7. 整理Android应用源代码分享
  8. 二、瞰景Smart3D软件安装及授权
  9. fckeditor 2.6 php,fckeditor = 2.6.4 任意文件上传漏洞
  10. DCMTK相关资料汇总
  11. 【多任务CTR】阿里ESMM:Entire Space Multi-Task Model: An Effective Approach for Estimating Post-Click Conve
  12. 计算机管理组合用户,Windows2000用户和计算机帐户管理
  13. AASM rule of scoring sleep stages using EEG signal
  14. NetCDF 文件的基本组成部分
  15. css盒心形的代码过程,如何使用CSS和D3实现用文字组成的心形动画效果(附代码)...
  16. 关于 SAP ABAP 报表的多语言显示问题试读版
  17. 一汽妈妈叫你来看跌停
  18. modis数据简介及批处理工具
  19. 常见六大 Web 安全攻防解析
  20. 当Docker运行碰上“连接被重置”

热门文章

  1. 搜索回溯——N皇后(hdu2553)
  2. Spring-data-jpa中用@ColumnTransformer注解加密,中文乱码问题(数据库正常,在java代码和页面中乱码)
  3. 【课程】MIT最新深度学习课程集
  4. JAVA—object映射转化为long类型方式
  5. 大一计算机专业学生如何在寒假充电?
  6. 常见运行时异常 java 114982568
  7. python-字符串与字节-0222
  8. mysql安装笔记190914
  9. python-函数与变量的定义-标识符的命名规范
  10. django-视图中的request对象的属性