TypeScript基础学习
学习来源:菜鸟教程
1.TypeScript简介
- TypeScript是JavaScript的超集,支持ECMAScript6标准。
- TypeScript是由微软开发的自由和开源的编程语言
- TypeScript设计目标是开发大型应用,它可以编译成纯JavaScript,编译出来的JavaScript可以运行在任何浏览器上
2.JavaScript与TypeScript的区别
TypeSCript是JavaScript的超集,扩展了JavaScript的语法,因此现有的JavaScript代码可以与TypeScript一起工作而无需做任何的修改,TypeScript通过类型注解提供编译时的静态类型检查。TypeSCript可处理已有的JavaScript代码,并且对其中的TypeScript代码进行编译。
3.TypeScript安装
命令行安装:npm install -g typescript
版本查看:$ tsc -v
macOS:sudo npm install -g typescript
4.TypeScript使用
第一步:新建helloworld.ts文件
第二步:输入代码
var msg : string = "hello world";
console.log(msg);
第三步:运行ts文件
tsc helloworld.ts
第四步:运行结果
会根据ts文件里面对应的内容,生成相应的js文件,可以在其他位置引用该文件,也可以直接node helloworld.js文件,测试文件生成结果
**我们可以同时编译多个文件 ,eg:
tsc hello1.ts hello2.ts hello3.ts
5.基础语法
注意事项:
TS区分大小写
每行指令后面分号可加可不加,最好加上
如果一行两个语句,一定要加,不然会报错
1.TS与面向对象
面向对象是对现实世界的理解和抽象,TS是一种面向对象的编程语言。面向对象中有两个概念:对象和类。
对象:类的实例,有状态和行为。例如:一个人是一个对象,状态有名字,性别。行为有:说话、工作等。
类:类是一个模板,描述一类对象的行为和状态。
方法:方法是类的操作的实现步骤。
eg1:Class_Object.ts
//定义类
class Person{
name():void{
console.log("FTTx")
}
}
//实例化对象
var obj = new Person();
//调用类中方法
obj.name();
eg2:tsc后生成的Class_Object.js
//定义类
var Person = /** @class */ (function () {
function Person() {
}
Person.prototype.name = function () {
console.log("FTTx");
};
return Person;
}());
//实例化对象
var obj = new Person();
//调用类中方法
obj.name();
eg3:node Class_Object.js
打印结果: FTTx
2.TS基础类型
1.any:声明为 any 的变量可以赋予任意类型的值。
2.number :双精度 64 位浮点值。它可以用来表示整数和分数。
3.string:一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式
4.boolean:表示逻辑值:true 和 false。
5.数组类型:声明变量为数组。// 在元素类型后面加上[] let arr: number[] = [1, 2]; // 或者使用数组泛型 let arr: Array<number> = [1, 2];
6.元组:元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。let x: [string, number]; x = ['FTTx', 1]; // 运行正常 x = [1, 'FTTx']; // 报错 console.log(x[0]); // 输出 FTTx
7.enum(枚举):枚举类型用于定义数值集合。enum Color {Red, Green, Blue}; let c: Color= Color.Blue; console.log(c); // 输出 2
8.void:用于标识方法返回值的类型,表示该方法没有返回值。function hello(): void {alert("Hello FTTx");}
9.null:表示对象值缺失。
10.undefined:用于初始化变量为一个未定义的值
11.never:never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
注意:TypeScript 和 JavaScript 没有整数类型。
2.1 Null与undefined类型
null
在 JavaScript 中 null 表示 "什么都没有"。
null是一个只有一个值的特殊类型。表示一个空对象引用。
用 typeof 检测 null 返回是 object。
undefined
在 JavaScript 中, undefined 是一个没有设置值的变量。
typeof 一个没有值的变量会返回 undefined。
Null 和 Undefined 是其他任何类型(包括 void)的子类型,可以赋值给其它类型,如数字类型,此时,赋值后的类型会变成 null 或 undefined。而在TypeScript中启用严格的空校验(--strictNullChecks)特性,就可以使得null 和 undefined 只能被赋值给 void 或本身对应的类型
// 启用 --strictNullChecks
let x: number;
x = 1; // 运行正确
x = undefined; // 运行错误
x = null; // 运行错误
// 启用 --strictNullChecks
let x: number | null | undefined;
x = 1; // 运行正确
x = undefined; // 运行正确
x = null; // 运行正确
3.变量声明
变量是一种使用方便的占位符,用于引用计算机内存地址。
变量可以看做错春数据的容器。
变量命名规则:
变量名称可以包含字母和数字
除了_和$符外,不能包含其他字符,包括空格
变量不能以数字作为开头。
声明变量的方式:
1. var [变量名] : [类型] = 值;
2. 若没有初始值,则声明后的变量值为undefined
3. 若没有初始类型,则声明后的变量类型为any
4. 若没有类型和初始值,则类型为any,初始值为undefined
TS遵循强类型,如果将不同的类型赋值给变量会编译错误:eg:
var num : number = 'name' ; //此代码会报错,因为期待类型为数字,而你却赋值了一个字符串,这是不允许的
3.1类型断言 (Type Assertion)
类型断言学习来源
类型断言可以手动指定一个值的类型,即允许变量从一个类型更改成为另一种类型。它之所以不能称之为类型转换拿,是因为类型转换通常意味着某种运行时的支持,但是类型断言纯粹是一个编译时的语法,同时,它也是一种为编译器提供关于如何分析代码的正确方法。
类型断言方式:
<类型> 值
或
值 as 类型(推荐使用as)
eg1:类型断言
function func(val: string | number): number {
if ((<string>val).length) {
return (<string>val).length
} else {
return val.toString().length
}
}
或
function func(val: string | number): number {
if ((val as string).length) {
return (val as string).length
} else {
return val.toString().length
}
}
在TS中,上面的例子,不可以直接if(val.length),因为参数val是一个联合类型,既可以是字符串也可以是数值类型。
访问联合类型值的属性,这个属性必须是所有可能类型的共有属性,而length不是共有属性,val此时的类型还位置,所以编译不能通过,所以我们应该使用类型断言
3.2类型推断
当类型没有给出时,TypeScript编译器利用类型推断来推断类型。如果由于缺乏声明而不能推断类型,那么它的类型被视作默认的动态any类型。
var num = 2; //类型推断为number
console.log("num的值为:"+num);
num = '12' //编译错误,我们已经推断该变量的数据类型为number,所以不能赋值为字符串。
//报错结果 error TS2322: Type '"12"' is not assignable to type 'number'.
3.3变量作用域
变量作用域指定了变量定义的位置。
程序中变量的可用性由变量作用域决定。
TypeScript有一下三种作用域:
1.全局作用域-全局变量定义在程序结构的外部,它可以在代码的任何位置使用
2.类作用域-这个变量也可称为字段。类变量声明在一个类里面,但类的方法在外面。该变量可以通过类的对象来访问。类变量可以是静态的,静态的变量可以通过类型直接访问。
3.局部作用域-局部变量,局部变量只能在它声明的一个代码块中使用。
eg:不同作用域内的变量的使用方法:
var global_num = 12 // 全局变量
class Numbers {
num_val = 13; // 实例变量
static sval = 10; // 静态变量
storeNum():void {
var local_num = 14; // 局部变量
}
}
console.log("全局变量为: "+global_num)
console.log(Numbers.sval) // 静态变量
var obj = new Numbers();
console.log("实例变量: "+obj.num_val)
4.运算符
算数运算符
+ 加法
- 减法
* 乘法
/ 除法
% 取模
++ 自增
-- 自减
关系运算符
== 等于
!= 不等于
> 大于
< 小于
>= 大于或等于
<= 小于或等于
逻辑运算符
&& and
|| or
! not
短路运算符
&& 要求符号两端皆为true,所以当左边已经为false后,直接返回false,后面的语句将不再执行
|| 要求两端有一端为true即可,所以当左边的值已经为true后,直接返回true,后面的运算就不用再进行了
4.1位运算符
4.2赋值运算符
var a : number = 12;
var b : number = 10;
a=b;
console.log("a=b",a); // a = b 10
a += b;
console.log('a += b',a); // a=a+b; 10+10=20
a -= b;
console.log('a -= b',a); // a=a-b; 20-10=10;
a *= b;
console.log('a *= b',a); // a=a*b; 10*10 = 100
a /= b;
console.log('a /= b',a); //a=a/b; 100/10=10
a %= b;
console.log('a %= b',a); //a=a%b 0
4.3三元运算符
用于判断表达式返回的布尔值,如果为true,就执行?后的语句,如果是false,就执行:后面的语句
格式:expression ? exp1 : exp2
若expression为true,则执行exp1,否则执行exp2
var myname : string = 'FTTx';
typeof(myname)==='string'?console.log("myname是一个字符串"):console.log('其他类型')
4.4类型运算符
typeof,返回某个变量或表达式的类型,eg:typeof(12) //number
instanceof,用来判断方法或接口类型
eg:instanceof的使用
class Person{
pname:'fttx';
eat(){
console.log('i like tomatoes')
}
}
var p:Person = new Person();
console.log(p instanceof Person) //true,因为p是Person的实例
console.log(p instanceof Object) //true,因为p是一个对象实例
console.log(p,typeof p); //Person{} 'object'
4.5其他运算符
- 负号运算符 4 ---> -4
+ 连接运算符 'hello'+'world' ---> 'helloworld'
5.函数
1.普通函数
1.与JavaScript略显不同的是,ts中若定义的函数有返回值,会在函数名称后面标记返回值的类型,当然如果不确定具体的类型也可以不标注。
function wonder:string(){
return 'what a beautiful girl!'
}
wonder();
2.如果函数带有参数且类型固定,需要在参数后面标注参数类型
function add(x:number,y:number):number{
return x+y
}
console.log(add(1,3))
参数类型
1.必需参数,一旦明确了参数的个数和类型,那么在调用函数的时候,相应的参数和类型也要确定下来,多或者少参数都会报错
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // 错误,缺少参数
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
2.可选参数,可以选择传也可以不传,即参数可以少但不可以多,并且可选参数一定要放在必须参数的后面,加上?
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"); // 正确
3.默认参数,即有默认值的参数,需要注意的是,参数不能同时设置成为默认参数和可选参数
function calculate_discount(price:number,rate:number = 0.50) {
var discount = price * rate;
console.log("计算结果: ",discount);
}
calculate_discount(1000)
calculate_discount(1000,0.30)
如果没有传rate的值时,rate默认为0.5,如果传了,rate为所传的值
4.剩余参数
如果我们不知道要传入参数的个数,就可以使用剩余参数来定义
function addNumbers(...nums:number[]) {
var i;
var sum:number = 0;
for(i = 0;i<nums.length;i++) {
sum = sum + nums[i];
}
console.log("和为:",sum)
}
addNumbers(1,2,3)
addNumbers(10,10,10,10,10)
2.匿名函数
没有函数名,可以将匿名函数赋值给一个变量,变量调用,也可以匿名函数自执行
var fn = function(){}
console.log(fn())
或
(function(){})()
3.构造函数
TypeScript 也支持使用 JavaScript 内置的构造函数 Function() 来定义函数:
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
console.log(x);
4.递归函数
递归函数就是在函数内调用函数本身
function factorial(number) {
if (number <= 0) { // 停止执行
return 1;
} else {
return (number * factorial(number - 1)); // 调用自身
}
};
console.log(factorial(6)); // 输出 720
5.Lambda函数(箭头函数)
var foo = (x:number)=>10 + x
console.log(foo(100)) //输出结果为 110
var func = (x)=> {
if(typeof x=="number") {
console.log(x+" 是一个数字")
} else if(typeof x=="string") {
console.log(x+" 是一个字符串")
}
}
func(12)
func("Tom")
6.函数重载
函数重载是方法名相同,参数不同,返回值可以相同也可以不同,每个重载的方法(或者构造函数)都要有一个独一无二的参数列表。
函数重载主要是参数不同,可以具体体现为参数的数量不同,参数的类型不同,参数类型的顺序不同
如果参数类型不同,则参数类型应设置为 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");
6.Number
1.我们可以通过var num =new Number(value),将参数转换成Number类型,如果不能转换,则返回NaN( typeof(NaN); //number)
2.number属性有:MAX_VALUE、MIN_VALUE、NaN、NEGATIVE_INFINITY、POSITIVE_INFINITY、prototype、constructor
3.number的方法有:
1.toExponential() 把对象的值转换成指数计数法
2.toFixed() 数字转换成字符串,并指定小数点位数
3.toLocaleString() 数字转换成字符串,使用本地数字格式顺序
4.toPrecision() 把数字转换成指定长度,包括小数点前后所有数长度总和
5.toString() 将数字转换成字符串,默认十进制,可以在()中传递2即转换成二进制等
6.valueOf() 返回一个Number对象的原始数字值
7.String
string 对象用于处理文本(字符串)
var txt = new String("string");
或者更简单方式:
var txt = "string";
7.1 String对象属性
1.constructor 对创建该对象的函数的引用。
2.length 返回字符串的长度
3.prototype 允许您向对象添加属性和方法。
function employee(id:number,name:string) {
this.id = id
this.name = name
}
var emp = new employee(123,"admin")
employee.prototype.email="admin@runoob.com" // 添加属性 email
console.log("员工号: "+emp.id)
console.log("员工姓名: "+emp.name)
console.log("员工邮箱: "+emp.email)
7.2 String方法
1. charAt() 返回在指定位置的字符。 var myname='Ftcx' console.log(myname.charAt(2)); //c
2. charCodeAt() 返回在指定的位置的字符的 Unicode 编码。var myname='Ftcx' console.log(myname.charCodeAt(2)); //99
3. concat() 连接两个或多个字符串,并返回新的字符串 var myname ='Ftcx';var youname='Cysx';console.log(myname.concat(youname)) //FtcxCysx
4. indexOf() 返回某个指定的字符串值在字符串中首次出现的位置。var myname ='Ftcx'; console.log(myname.indexOf('c')) //2 如果没有则返回-1
5. lastIndexOf() 从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。
var str1 = new String( "This is string one and again string" );
var index = str1.lastIndexOf( "string" );
console.log("lastIndexOf 查找到的最后字符串位置 :" + index ); // 29
6.match() 查找找到一个或多个正则表达式的匹配。
var str="The rain in SPAIN stays mainly in the plain";
var n=str.match(/ain/g); // ain,ain,ain
7.replace() 替换与正则表达式匹配的子串
var re = /(\w+)\s(\w+)/;
var str = "zara ali";
var newstr = str.replace(re, "$2, $1");
console.log(newstr); // ali, zara
8. search() 检索与正则表达式相匹配的值
var re = /apples/gi;
var str = "Apples are round, and apples are juicy.";
if (str.search(re) == -1 ) {
console.log("Does not contain Apples" );
} else {
console.log("Contains Apples" );
}
9.slice() 提取字符串的片断,并在新的字符串中返回被提取的部分。
10.split() 把字符串分割为子字符串数组。
var str = "Apples are round, and apples are juicy.";
var splitted = str.split(" ", 3);
console.log(splitted) // [ 'Apples', 'are', 'round,' ]
11.substr() 从起始索引号提取字符串中指定数目的字符。
12.substring() 提取字符串中两个指定的索引号之间的字符。var str = 'ftcxy';console.log(str.substring(1,4)); //tcx
13. toLocaleLowerCase() 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射。
14.toLocaleUpperCase() 据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射。
15.toLowerCase() 把字符串转换为小写。
16. toUpperCase() 把字符串转换为大写。
17. toString() 返回字符串。
18.valueOf() 返回指定字符串对象的原始值。
8.数组
1.数组声明:var sites:string[]; sites = ["Google","Runoob","Taobao"]
2.如果数组在声明时没有指定类型,则会被认为是any类型,在初始化时会根据第一个元素的类型来推断数组的类型。
3.var nums:number[] = [1,2,3,4]
4.在以上的两个声明中我们可以看出,因为数组内不仅仅有一个元素,所以在声明类型时我们可以在后面加上一个[],比如string[]/number[]
8.1多维数组
var multi:number[][] = [[1,2,3],[23,24,25]]
console.log(multi[0][0])
console.log(multi[0][1])
console.log(multi[0][2])
console.log(multi[1][0])
console.log(multi[1][1])
console.log(multi[1][2])
//输出结果1 2 3 23 24 25
8.2数组方法
1.concat() 连接两个或更多的数组,并返回结果。
2.every() 检测数值元素的每个元素是否都符合条件。
function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
console.log("Test Value : " + passed ); // false
3. filter() 检测数值元素,并返回符合条件所有元素的数组。
4. forEach() 数组每个元素都执行一次回调函数。
5. indexOf() 搜索数组中的元素,并返回它所在的位置。如果搜索不到,返回值 -1,代表没有此项。
6. join() 把数组的所有元素放入一个字符串。
7. lastIndexOf() 返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
8. map() 通过指定函数处理数组的每个元素,并返回处理后的数组。
9. pop() 删除数组的最后一个元素并返回删除的元素
10.push() 向数组的末尾添加一个或更多元素,并返回新的长度。
11.reduce() 将数组元素计算为一个值(从左到右)。
12.reduceRight() 将数组元素计算为一个值(从右到左)。
13.reverse() 反转数组的元素顺序。
14.shift() 删除并返回数组的第一个元素。
15.slice() 选取数组的的一部分,并返回一个新数组。
16.some() 检测数组元素中是否有元素符合指定条件。
17.sort() 对数组的元素进行排序。
18.splice() 从数组中添加或删除元素。
19.toString() 把数组转换为字符串,并返回结果。
20.unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
9.元组
1.我们知道数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。元组中允许存储不同类型的元素,元组可以作为参数传递给函数。
2.声明一个元组并初始化:var mytuple = [10,"Runoob"];访问元组和访问数组的方法相同,都可以利用下标来访问
3.元组的添加push、删除pop、利用下标更新元组中某个值,对元组进行解构的方法与数组相同。
10.联合类型
联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。
注意:只能赋值指定的类型,如果赋值其它类型就会报错。
var val:string|number
val = 12
console.log("数字为 "+ val)
val = "Runoob"
console.log("字符串为 " + val)
11.TypeScript接口
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
var customer:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
console.log("Customer 对象 ")
console.log(customer.firstName)
console.log(customer.lastName)
console.log(customer.sayHi())
var employee:IPerson = {
firstName:"Jim",
lastName:"Blakes",
sayHi: ():string =>{return "Hello!!!"}
}
console.log("Employee 对象 ")
console.log(employee.firstName)
console.log(employee.lastName)
需要注意接口不能转换为 JavaScript。 它只是 TypeScript 的一部分。
11.1接口和数组
接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。
interface namelist {
[index:number]:string
}
var list2:namelist = ["John",1,"Bran"] / 错误元素 1 不是 string 类型
interface ages {
[index:string]:number
}
var agelist:ages;
agelist["John"] = 15 // 正确
agelist[2] = "nine" // 错误
11.2接口继承
接口继承就是说接口可以通过其他接口来扩展自己。Typescript 允许接口继承多个接口。继承使用关键字 extends。
单接口继承语法格式:
Child_interface_name extends super_interface_name
多接口继承语法格式:
Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name,继承多个接口时,将多个接口中间用,分隔开
eg1:单继承实例
interface Person {
age:number
}
interface Musician extends Person {
instrument:string
}
var drummer = <Musician>{};
drummer.age = 27
drummer.instrument = "Drums"
console.log("年龄: "+drummer.age)
console.log("喜欢的乐器: "+drummer.instrument)
eg2:多继承实例
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
interface Child extends IParent1, IParent2 { }
var Iobj:Child = { v1:12, v2:23}
console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)
12.类
TypeScript 是面向对象的 JavaScript。类描述了所创建的对象共同的属性和方法。TypeScript 支持面向对象的所有特性,比如 类、接口等。
TypeScript类定义的方式:class class_name { // 类作用域}
定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):字段 − 字段是类里面声明的变量。字段表示对象的有关数据。构造函数 − 类实例化时调用,可以为类的对象分配内存。方法 − 方法为对象要执行的操作。
eg1:类的简单实例
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("函数中显示发动机型号 : "+this.engine)
}
}
// 创建一个对象
var obj = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : "+obj.engine)
// 访问方法
obj.disp()
12.1类的继承
eg1:类的继承
class Shape {
Area:number
constructor(a:number) {
this.Area = a
}
}
class Circle extends Shape {
disp():void {
console.log("圆的面积: "+this.Area)
}
}
var obj = new Circle(223);
obj.disp()
// 223
eg2:类的多重继承
class Root {
str:string;
}
class Child extends Root {}
class Leaf extends Child {} // 多重继承,继承了 Child 和 Root 类
var obj = new Leaf();
obj.str ="hello"
console.log(obj.str)
// hello
12.2继承类的方法重写
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
class PrinterClass {
doPrint():void {
console.log("父类的 doPrint() 方法。")
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 调用父类的函数
console.log("子类的 doPrint()方法。")
}
}
12.3static关键字
static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。类内的属性,需要实例化之后.属性名称调用,而静态属性可以直接属性名.调用
eg1:静态属性、静态方法的使用
class StaticMem {
static num:number;
static disp():void {
console.log("num 值为 "+ StaticMem.num)
}
}
StaticMem.num = 12 // 初始化静态变量
StaticMem.disp() // 调用静态方法
12.4 instanceof运算符
instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。
eg1:instanceof 可以用来判断某个对象是否是某个类实例化而来的
class Person{ }
var obj = new Person()
var isPerson = obj instanceof Person;
console.log("obj 对象是 Person 类实例化来的吗? " + isPerson);
12.5 访问控制修饰符
TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。
public(默认) : 公有,可以在任何地方被访问。
protected : 受保护,可以被其自身以及其子类和父类访问。
private : 私有,只能被其定义所在的类访问。
eg:访问控制修饰符
class Encapsulate {
str1:string = "hello"
private str2:string = "world"
}
var obj = new Encapsulate()
console.log(obj.str1) // 可访问
console.log(obj.str2) // 编译错误, str2 是私有的
12.6 类和接口
interface ILoan {
interest:number
}
class AgriLoan implements ILoan {
interest:number
rebate:number
constructor(interest:number,rebate:number) {
this.interest = interest
this.rebate = rebate
}
}
var obj = new AgriLoan(10,1)
console.log("利润为 : "+obj.interest+",抽成为 : "+obj.rebate )
13 对象
对象是一组包含键值对的实例。值可以是标量(number/string/boolean)、函数、数组、对象等
eg1:普通对象的定义
var sites = {
site1: "Hello",
site2: "World",
sayHello: function () { } // 类型模板
};
sites.sayHello = function () {
console.log("hello " + sites.site1);
};
sites.sayHello();
eg2:对象可以作为参数传递给函数
var sites = {
site1:"Runoob",
site2:"Google",
};
var invokesites = function(obj: { site1:string, site2 :string }) {
console.log("site1 :"+obj.site1)
console.log("site2 :"+obj.site2)
}
invokesites(sites)
13.1 鸭子类型(Duck Typing)
1.鸭子类型(英语:duck typing)是动态类型的一种风格,是多态(polymorphism)的一种形式。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
2.可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
3.在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
interface IPoint {
x:number
y:number
}
function addPoints(p1:IPoint,p2:IPoint):IPoint {
var x = p1.x + p2.x
var y = p1.y + p2.y
return {x:x,y:y}
}
// 正确
var newPoint = addPoints({x:3,y:4},{x:5,y:1})
// 错误
var newPoint2 = addPoints({x:1},{x:4,y:3})
14命名空间
命名空间最明确的目的就是解决重名问题,命名空间定义了标识符的可见范围,一个标识符可以在不同的命名空间中定义,它在不同命名空间的含义是互不相干的,这样在一个新的命名空间内可以定义任何标识符,他们不会与现有的标识符进行冲突,因为都存在于不同的命名空间中。
eg1:不同文件中,命名空间的使用
IShape.ts 文件代码:
namespace Drawing {
export interface IShape {
draw();
}
}
Circle.ts 文件代码:
/// <reference path = "IShape.ts" />
namespace Drawing {
export class Circle implements IShape {
public draw() {
console.log("Circle is drawn");
}
}
}
Triangle.ts 文件代码:
/// <reference path = "IShape.ts" />
namespace Drawing {
export class Triangle implements IShape {
public draw() {
console.log("Triangle is drawn");
}
}
}
14.1嵌套命名空间
命名空间支持嵌套,即你可以将命名空间定义在另外一个命名空间里头。
namespace Runoob {
export namespace invoiceApp {
export class Invoice {
public calculateDiscount(price: number) {
return price * .40;
}
}
}
}
15 TypeScript模块
1.TypeScript 模块的设计理念是可以更换的组织代码。
2.模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。
3.两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。
4.模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于 Node.js 的 CommonJS 和服务于 Web 应用的 Require.js。此外还有有 SystemJs 和 Webpack。
eg:
IShape.ts 文件代码:
/// <reference path = "IShape.ts" />
export interface IShape {
draw();
}
Circle.ts 文件代码:
import shape = require("./IShape");
export class Circle implements shape.IShape {
public draw() {
console.log("Cirlce is drawn (external module)");
}
}
Triangle.ts 文件代码:
import shape = require("./IShape");
export class Triangle implements shape.IShape {
public draw() {
console.log("Triangle is drawn (external module)");
}
}
TestShape.ts 文件代码:
import shape = require("./IShape");
import circle = require("./Circle");
import triangle = require("./Triangle");
function drawAllShapes(shapeToDraw: shape.IShape) {
shapeToDraw.draw();
}
drawAllShapes(new circle.Circle());
drawAllShapes(new triangle.Triangle());
使用 tsc 命令编译以上代码(AMD):
tsc --module amd TestShape.ts
使用 tsc 命令编译以上代码(Commonjs):
tsc --module commonjs TestShape.ts
16声明文件
TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。
eg:我们想在某个文件中使用jQuery
$('#foo');
// 或
jQuery('#foo');
但是在 TypeScript 中,我们并不知道 $ 或 jQuery 是什么东西:
这时,我们需要使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对:
declare var jQuery: (selector: string) => any;
jQuery('#foo');
declare 定义的类型只会用于编译时的检查,编译结果中会被删除。
16.1声明文件
1.声明文件以.d.ts为后缀 eg:Ftxc.d.ts
2.声明文件或模块的语法格式如下:
declare module Module_Name {
}
3.TypeScript 引入声明文件语法格式:
eg:
**第一步:**这是一个第三方库
CalcThirdPartyJsLib.js 文件代码:
var Runoob;
(function(Runoob) {
var Calc = (function () {
function Calc() {
}
})
Calc.prototype.doSum = function (limit) {
var sum = 0;
for (var i = 0; i <= limit; i++) {
sum = sum + i;
}
return sum;
}
Runoob.Calc = Calc;
return Calc;
})(Runoob || (Runoob = {}));
var test = new Runoob.Calc();
**第二步:如果我们想在 TypeScript 中引用上面的代码,则需要设置声明文件 Calc.d.ts**
declare module Runoob {
export class Calc {
doSum(limit:number) : number;
}
}
声明文件不包含实现,它只是类型声明,把声明文件加入到 TypeScript 中:
CalcTest.ts 文件代码:
/// <reference path = "Calc.d.ts" />
var obj = new Runoob.Calc();
// obj.doSum("Hello"); // 编译错误,因为doSum中要求所传参数为number类型
console.log(obj.doSum(10));
最后一步:编译ts文件
tsc CalcTest.ts