TS学习-初步
一、TypeScript 简介
1、TypeScript是什么?
TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准。
TypeScript 由微软开发的自由和开源的编程语言。
TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
TypeScript 是一种给 JavaScript 添加特性的语言扩展。增加的功能包括:
类型批注和编译时类型检查,类型推断,类型擦除,接口,枚举,Mixin,泛型编程,名字空间,元组,Await
2、TS配置
安装好NodeJS后,以管理员身份运行终端,使用npm -g install ts-node typescript
命令进行全局安装
如在VS Code中开发,请安装TSLint、TypeScript Hero、Bracket Pair Colorizer
等插件
新建文件后缀为.ts。
使用代码来输出 “Hello World” :
const hello : string = "Hello World!"
console.log(hello)
二、TypeScript 基础语法
TS程序 = 模块+函数+变量+语句和表达式+注释
构成
一个.ts
文件,通过tsc
命令编译,得到.js
代码,最后我们使用node命令执行该js代码。
1、变量声明
TypeScript 变量的命名规则:
- 变量名称可以包含数字和字母。
- 除了下划线 _ 和美元 $ 符号外,不能包含其他特殊字符,包括空格。
- 变量名不能以数字开头。
变量使用前必须先声明,可以使用 var 来声明变量。
2、变量作用域
TypeScript 有以下几种作用域:
- 全局作用域 − 全局变量定义在程序结构的外部,它可以在你代码的任何位置使用。
- 类作用域 − 这个变量也可以称为 字段。类变量声明在一个类里头,但在类的方法外面。 该变量可以通过类的对象来访问。类变量也可以是静态的,静态的变量可以通过类名直接访问。
- 局部作用域 − 局部变量,局部变量只能在声明它的一个代码块(如:方法)中使用。
三、TypeScript初步
以下就Typescript涉及前端框架Angular和相关特性的一些知识点进行介绍。
1、let和const
不使用var
,使用let
或const
申明变量,并加上类型说明,且作用域为块级即以{}
为界。
使用let
声明变量,一个变量同时只能声明一次,否则会报错。
通过const
声明的变量只能在声明是被赋值,即声明后的变量被赋值后不能再改变(实际上是这个变量所指向的内存地址不能改动)。
let lang: string = 'TypeScript';//如果省略类型说明,TS也可进行自动推断
lang = 1010;//error! 如果需要可以使用联合类型:let lang: number | string = 'TS';
let age: number = 89;
let age = 64;//error!
const pi: number = 3.14159;//pi以后不可改变,类似常量
pi = 3.14;//error!
2、解构
将对象、数组中的元素拆分到指定变量中,以方便使用。
//解构数组
let input = [89, 64, 2018, 10];
let [first, second] = input;//注意使用[]
console.log(first); // 89
console.log(second); // 64
let [one, ...others] = input; //剩余变量
console.log(...others);
//展开
let newArr = [89, ...others, 18];
console.log(newArr);
//解构对象
let o = {
a: "foo",
b: 12,
c: "bar"
};
let {a, b} = o;//注意使用{},且变量名需与对象中道属性名一致
console.log(a, b);
3、函数
函数是一组一起执行一个任务的语句。
您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的。
函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。
示例:
function () {
// 函数定义
console.log("调用函数")
}
函数返回值
语法格式如下:
function function_name():return_type {
// 语句
return value;
}
- return_type 是返回值的类型。
- return 关键词后跟着要返回的结果。
- 一般情况下,一个函数只有一个 return 语句。
- 返回值的类型需要与函数定义的返回类型(return_type)一致。
可选参数
在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ?。
如下所示:
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // 正确
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
注:可选参数必须跟在必需参数后面。 如果上例我们想让 firstName 是可选的,lastName 必选,那么就要调整它们的位置,把 firstName 放在后面。
如果都是可选参数就没关系。
剩余参数
有一种情况,我们不知道要向函数传入多少个参数,这时候我们就可以使用剩余参数来定义。
剩余参数语法允许我们将一个不确定数量的参数作为一个数组传入。
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
函数的最后一个命名参数 restOfName 以 … 为前缀,它将成为一个由剩余参数组成的数组,索引值从0(包括)到 restOfName.length(不包括)。
匿名函数
匿名函数是一个没有函数名的函数。
匿名函数在程序运行时动态声明,除了没有函数名外,其他的与标准函数一样。
我们可以将匿名函数赋值给一个变量,这种表达式就成为函数表达式。
语法格式如下:
var res = function( [arguments] ) { ... }
构造函数
TypeScript 也支持使用 JavaScript 内置的构造函数 Function() 来定义函数:
语法格式:
var res = new Function ([arg1[, arg2[, ...argN]],] functionBody)
- arg1, arg2, … argN:参数列表。
- functionBody:一个含有包括函数定义的 JavaScript 语句的字符串。
函数重载
重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
如果参数类型不同,则参数类型应设置为 any。
参数数量不同你可以将不同的参数设置为可选。
以下实例定义了参数类型与参数数量的不同:
function disp(s1:string):void;
function disp(n1:number,s1:string):void;
function disp(x:any,y?:any):void {
console.log(x);
console.log(y);
}
disp("abc")
disp(1,"xyz");
输出结果为:
abc
undefined
1
xyz
定义函数重载需要定义重载签名和一个实现签名。
重载签名定义函数的形参和返回类型,没有函数体。一个函数可以有多个重载签名(不可调用)
4、类class
类是属性(有些什么)和函数(能干什么)的集合,是生成对象(Object)或类实例的模板。
定义方式如下:
class class_name {
// 类作用域
}
定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):
- 字段 − 字段是类里面声明的变量。字段表示对象的有关数据。
- 构造函数 − 类实例化时调用,可以为类的对象分配内存。
- 方法 − 方法为对象要执行的操作。
更具体一点的使用案例:
//类的定义和使用
class MyInfo { //class是关键字,类名默认全部大写首字母
name: string; //属性
weather: string; //属性
constructor(name: string, weather: string){ //构造函数,一般用于初始化。如果没有,TS会自动生成一个,以备用new创建类实例时调用。
this.name = name;
this.weather = weather;
}
printInfo(): void { //其它函数,无返回值
console.log(`Hello, ${this.name}.`);
console.log(`Today is ${this.weather}.`);
}
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象,即该类的实例
myData.printInfo();
类中的属性和函数都有访问权限,默认为public即全局可访问,其次为protected即可在类的内部和其子类的内部可访问,最后为private,只能在该类内部可访问。
//访问权限
class MyInfo { //class是关键字,类名默认全部大写首字母
public name: string; //public属性,可省略
private _weather: string; //私有属性,习惯以_开头进行命名
constructor(name: string, weather: string){ //构造函数,一般用于初始化
this.name = name;
this._weather = weather;
}
printInfo(): void { //其它函数
this._test();
console.log(`Hello, ${this.name}.`);
console.log(`Today is ${this._weather}.`);
}
private _test(): void {
console.log('You can not call me outside!');
}
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象
console.log(myData._weather); //error!
myData._test(); //error
myData.printInfo();
存取器-getter、setter
当在类外部时,建议设置getter和setter操作其private属性,即使public属性也如此。
//getter和setter
class MyInfo { //class是关键字,类名默认全部大写首字母
private readonly _name: string; //私有属性,外部不可访问。readonly使其只能在初始化时赋值,以后不可更改。
private _weather: string; //私有属性,习惯以_开头进行命名
constructor(name: string, weather: string){ //构造函数,一般用于初始化
this._name = name;
this._weather = weather;
}
get name(): string {
return this._name;
}
set name(value: string) { //error! _name有readonly属性
this._name = value;
}
get weather(): string {
return this._weather;
}
set weather(value: string) {
this._weather = value;
}
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象
console.log(myData.name, myData.weather);
myData.weather = 'sunny'; //OK
myData.name = 'Wang'; //error!
console.log(myData);
继承
TypeScript 支持继承类,即我们可以在创建类的时候继承一个已存在的类,这个已存在的类称为父类,继承它的类称为子类。
类继承使用关键字 extends,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。
TypeScript 一次只能继承一个类,不支持继承多个类,但 TypeScript 支持多重继承(A 继承 B,B 继承 C)。
语法格式:
class child_class_name extends parent_class_name
具体实例如下:
class Animal {
// 当构造函数传入的参数加上了“访问权限控制符”,则同时会声明同名类属性,并赋值
constructor(public name: string) { }
protected log(message: string) {
console.log(message);
}
move(distanceInMeters: number = 0) {
this.log(`${this.name} moved ${distanceInMeters}m.`);//请注意name来自何处
this.log('==============');
}
}
class Horse extends Animal {
constructor(name: string) {
super(name); // 通过super调用父类构造器
}
run(distanceInMeters = 50) { //自己独有的函数
this.log("Clop, clop...");
super.move(distanceInMeters); // 通过super调用父类方法
}
}
class Eagle extends Animal {
constructor(name: string) { super(name); }
reborn() { //自己独有的函数
console.log('Reborn? It is a joke, hahaha!');
}
}
let tom: Horse = new Horse("Tommy the Palomino");
tom.run(8964);
let sam: Eagle = new Eagle("Sammy the Hawk");
sam.move(1024);//sam的move函数来自何处?
sam.reborn();
5、模块Module
TypeScript 模块的设计理念是可以更换的组织代码。
模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。
对于大型的项目,我们需要使用模块进行管理。每个 .ts 文件就是一个模块,通过 export 来对外部模块暴露元素,通过 import 来引入模块。
导出export
的语法格式:
// 文件名 : SomeInterface.ts
export interface SomeInterface {
// 代码部分
}
导入import
的语法格式:
import someInterfaceRef = require("./SomeInterface");
四、小结
Typescript是一门基于JavaScript之上的语言,重点解决了JavaScript自由类型系统的问题。使用Typescript可以大大提高代码的可靠程度。
用惯了Javascript之后再去使用Typescript会感觉到很麻烦,严格的数据类型,严格的返回值类型,也相对的是规范程度的提高。
但是一旦项目成型,开发起来会很轻松,也有利于维护。
总而言之,多学无妨,不管是否是开发人员,拓宽自己的视野、接受新知识一种享受是一种提升。