TypeScript是JavaScript的超集,它的作者是著名的C#之父(名字我忘了)。作为后者的超集,Typescript(以下简称为tsc)拓展了JS,真正的将js从玩具语言变成一种工程语言,一种强类型的语言。并且,tsc的标准是根据每年的ECMA提案来预先实现的,也就是说,tsc兼容未来的ES7,ES8…提前为将来的ES标准打下基础。 学习tsc,不亏!
完事,安装tsc的npm包,就是为了使用它自带的功能,将.ts文件编译成.js文件,从而兼容各种平台及浏览器,编译的命令行如下:
$ cd your File_path $ tsc File_name.tsOK,执行完,发现在.ts的同目录下,自动编译完成一个同名的.ts文件。
1.基本类型检测
在js中,命名一个变量通常不用指定类型,tsc弥补了这个劣势,加入类型监测,形如:
let a:number = 1; //OK let a:string = 1; //error 类型检测的语法,就是在变量屁股后面缀上 :类型2.数组的类型检测:
let arr:number[]=[1,2,3]; //ok 类型+[] let brr:Array<number>=[4,5,6]; //OK 数组泛型+尖括号< 类型 >3.元组类型 Tupe
let X:[number,string]; x=[1,'hello']; //OK x=[1,2]; //type error 元组类型适用于已知个数和元素类型的数组。拼接:跟ES6一样,通过(``)来实现,【`】为Tab上面的按键。
for eg :
let hi= (` hello, wrold! `); //输出 hello,world!字符串模板:提供一种更优雅的书写方式:${ 变量名}
for eg:
let names:string = 'xiaoming'; let age:number = 23; let sentence:string = (` hello,my name is ${names},my age is ${age} `);编译后的js文件为:
var names = 'xiaoming'; var age = 23; var sentence = ("\nhello,my name is " + names + ",my age is " + age + "\n"); document.body.innerHTML = sentence;有时候不希望tsc太严格,对于部分变量或者数据开个后门,就可以声明Any 任意类型。
let不能重复定义,我就用var来演示。
Any类型也可以像数组的第一种定义方法一样,形如:
Array: let arr:number[]=[1,2,3]; // OK 数字的组合,可不就是数组吗? 字符串组、布尔值组... let brr:string[] = ['a','b','c']; let crr:boolean[] = [true,false]; Any: let drr:any[]=[1,'2',true]; // OK 只知道是个类似于数组的数据类型,但是对元素的类型不做限制。void类型表示空。常用在函数返回值,形如:
//注意函数返回值类型检测的写法 function foo():void{ alert('123'); };其实,void包含两种数据类型,就是null和undefind。
触类旁通,其实还有两个类型是null和undefind,如图所示:
如图所示,两个类型不仅自暴自弃,还拉对方下水,形成“你中有我,我中有你”的关系。
作用就是清楚的告诉编译器,我知道a是number类型的,不要给我搞事。 写法一:
let a:number =1; let b:any = <number>a ; //赋值第二种写法:
来看这样一段代码:
在这个for循环中,有一个setTimeout异步函数,循环5次,打印出的结果是什么呢?
可见,连续打印了5次5,为什么5次都是5 呢?因为setTimeout是一个异步函数,他会等待其他函数执行完,再执行,没有拿到i的最终结果,他不会执行。
究其本质,是因为for循环()中的作用域与{}中的作用域混淆了,如果将这两个作用域独立,那么setTimeout不会等待i的最终执行结果
将上述代码的var i改为let i这样,for 循环中的()部分就有了自己独立的块级作用域,所以每次setTimeout执行的时候就不会等待i的最终结果。 因此,代码结果如下图所示:
再来看一个对比:
将var 改为let
可见,两种声明,是一摸一样的输出,为什么呢? var的声名方式,是因为()和{}基本上可以视为同一作用域,而let的声名方式稍有不同,每次for(let i=0;i<5;i++)的迭代,都会创建一个新的作用域{},因此,每次的结果照样可以打印出来。 因为这里没有异步函数,即便二者的作用域不同(前者是一个全局作用域,后者是两个块级作用域),输出也是相同的。
总结:使用var或者let,如果当输入环节没有异步函数,无论再怎么变换作用域,那么输出相同,否则,输出不同。
定义了一次,就不能再次定义或者修改赋值。这种定义的方法,用于只读数据,没有修改权限的时候用。 eg:
const a = 1 ; const a = 2 ; //error普通结构赋值:
函数参数结构赋值:
注意:函数的参数在类型监测的时候,用结构赋值,需要冒号【:】。
输出:
可见,对于未知元素(数组中的成员),默认是对象,当打印输出的时候,会将其当做数组对象来看待。
直接结构,这里要注意,新定义的对象中,key键名,一定要与被解构对象的属性名字相同,且不能跳跃式解构。
下图是错误示范:
那么同理,如果在一个方法中返回对象,同样也可以被解构。
如果对象存在嵌套现象,可以使用冒号表达式:
还是使用…语法,进行数组或者对象的浅拷贝。
数组展开,形如:
对象展开,形如:
对象展开时,所有传入的键值对,一旦有重复,按照覆盖原则,后面的value会覆盖前面的。执行顺序是从左到右。
确定的参数要现在第一个,不能把可选参数写在第一位。
在往常的js代码中,不可以人为的暂停或者恢复代码的运行,但是现在有了yield关键字,就可以将函数的执行流程化,从而让我们有条不紊的控制步骤。
function* foo(){ console.log(1); yield; //设置断点,下同 console.log(2); yield; console.log(3); yield; }; /*设置断点以后,并不能直接foo.next(),因为其内部没有next方法。 *必须重新赋值,再调用。 */ let zoo = foo(); //这里有三个断点,简单的可以理解为,把函数的执行流程划分为三个阶段,每次的调用,只是执行其中的一个阶段。 zoo.next();//1 zoo.next();//2 zoo.next();//3作用一:主要用于声明匿名函数,简化代码。
var sum = (a,b)=>a+b 上式等价于: var sum = function (a,b){ retrun a+b; };作用二:消除this指针带来的歧义,优化执行上下文。
function getName (name) { this.name = name ; setInterval(function () { console.log('name is '+this.name)},1000) }; var john = new getName('jhon'); console.log(john) // 打印 name is (空)这里由于getName()是全局函数,就是window下的一个方法,但是console.log()时,由于window下并没有定义 window.name 属性,因此,打印出来的值是 undefind。
使用箭头函数改造:
function getName (name) { this.name = name ; setInterval(() => console.log('name is '+this.name)),1000) }; var john = new getName('jhon'); console.log(john) // 打印 name is jhonfor…in 循环对象的下标
var arr = [1, 2, 3, 4]; arr.name = 'myArr'; for (var n in arr) { console.log(n+'=='+arr[n]) } //输出0=1,1=2,2=3,3=4,name=myArrfor of 循环对象的key
var arr = [1, 2, 3, 4]; arr.name = 'myArr'; for (var n of arr) { console.log(n+'=='+arr[n]) } //输出0=1,1=2,2=3,3=4,undefind //还可以循环字符串 var arr ='hello,world!' for (var n of arr) { console.log(n) } //h,e,l,l,o,,w,o,r,l,d,!;forEach 循环循环对象的key值,并且可以循环对象的key值对应的value,但是不能循环数组之外新添加的属性
var arr = [1, 2, 3, 4]; arr.name = 'myArr'; arr.forEach(function (n,v) { console.log(n,v) }) //输出1,2,3,4,但是没有输出我们定义的name总结:for…in循环数组下标。forEach很体面,但是有局限性(不能访问数组外部定义的属性),for…of有点鸡肋,但是胜在使用场景广泛。
interface是一种类型,预先定义好一系列的属性的类型,然后供新的对象来使用它。
当然,接口中预先定义的变量,也可以规定/限制函数中的参数:
在es3中,javascript的继承只能通过原型链来继承,现在可以通过Class类来继承 。真不愧是“JAVA”script!
访问权限关键字: public 公共成员。 子类、父类内部都可以访问到。
private 私有成员。只允许在类中访问。
protected 超类的私有成员。但是在子类中仍然可以访问。
构造器Construcor:
//形如: constructor(){ name?string; }; 12345在构造器中,相当于新建了一个局部的作用域,在构造器中声明的变量、属性都是局部的,哪怕是在Class内部、构造器之外,也无法访问。
举例说明:
这时候,只要在构造器的name上增加关键字public,即可在class中全局访问:
类的继承 真的比基于原型链的继承更加优雅和简便。
