掌握了 TypeScript ,就相当于掌握了 JavaScript 语言的最新标准。前端三大框架中,Angular 2 开始基于 TypeScript 开发,所以最好的学习路线是js->ts->Angular。
安装TypeScript的compiler。compiler(编译器)的作用是把TS代码转换成JS代码;ES6规范是在2015年发布的,而目前所有主流的浏览器并没有完全支持ES6规范,所以用ES6写的东西并不能直接放在浏览器中去跑。
TypeScript 官网:http://www.typescriptlang.org
TypeScript 在线编译器:http://www.typescriptlang.org/play
TypeScript 中文网:https://www.tslang.cn/
TypeScript 中文gitbook:https://github.com/zhongsp/TypeScript
TypeScript 项目地址:https://github.com/Microsoft/TypeScript
$ sudo npm install -g typescript
//作用:添加按钮到body标签中
let putButton = function (text:string,info:any){
let button = document.createElement("button");
let p = document.createElement("p");
button.textContent = text;
document.body.appendChild(button);
document.body.appendChild(p);
button.onclick = function() {
alert(info);
};
}
//boolean类型
let flag:boolean;
let flag_1:boolean = false;
putButton("let flag:boolean;",flag);
putButton("let flag_1:boolean = false;",flag_1);
//number
let PI : number = 3.1415926535897932384626433;//圆周率
putButton("number>>>圆周率PI",PI);
putButton("number>>>圆直径5,周长",5*PI);
//字符串
let str_double_quotes:string = "双引号声明string";
let str_single_quote :string = '单引号声明string';
let str_accent :string = `上点号声明string`;//可内嵌${表达式}
putButton("string>>>"+str_accent+"${5*8}",`5*8的值:${5*8}`);
//数组,两种声明方式
let nums: number[] = [1, 2, 3,4];
let numList: Array = nums;
putButton("数组[1,2,3,4]",numList.toString());
//元组Tuple
let dog:[string,number] = ["蝴蝶犬",5];//元组是一个数组,允许元素类型不同
dog[3] = "岁了";//数组越界不报错,因为"dog"是string|number联合类型
// dog[4] = false;//错误
putButton("元组Tuple",dog[0]+dog[1]+dog[3]);
//enum 枚举
enum Xiyouji{
唐僧,悟空,八戒=3,沙僧,白龙马
}//手动指定索引下标
let tangseng:Xiyouji = Xiyouji.唐僧;
let wukong:string = Xiyouji[1];//手动声明索引,左边索引从零开始
let shaseng:string = Xiyouji[4];//手动声明索引,右边索引依次增加
putButton("enum>>>西游记",wukong);
//any 任意值
let 水牛:any = "shuiniu";
let shuiniu:number = 100;
水牛 = shuiniu;
putButton("any>>>水牛",水牛);
//void 空值,只能为null或undefined
let v:void = null;
v = undefined;
function f():void{ return v};//空返回值,有点奇怪
putButton("void>>>",f());
//null和undefined,默认情况下null和undefined是所有类型的子类型。其他类型的值一般都可以赋给它们。
let undef: undefined = null;
let nul: null = undefined;
putButton("null和undefined","null和undefined是所有类型的子类型");
//Never类型表示的是那些永不存在的值的类型
//never类型是任何类型的子类型,但没有类型是never的子类型
// 这意味着never可以赋值给任何类型,但没有任何类型可以赋值给never类型(除了never本身之外)
let neve:never ;//初值undefined
let go:string = neve;
//never表示永远不存在值的类型
function trueWhile():never{
while (true){}
}
putButton("never>>>",go);
//此方法在body标签中追加指定元素和内容
function setElement(elementName:string,contentText:any){
let e = document.createElement(elementName);
e.textContent = contentText;
document.body.appendChild(e);
}
与JavaScript相一致
1.var声明的变量,可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问。也就是说即使是这样也可以正常执行:
var productName = "Leather wallet";
alert(productName);
2.const 常量,与let具有相同的作用域。 let声明的变量具有块级作用域,也就是说被try,if,while等块包围时,外部不能访问。可以有效避免var定义的各种问题。JavaScript本身具备let,IE11支持,参考:
遍历一个字符串数组,var的声明:
function forStrVar():void {
let str: string[] = ["极客园地", "BitMan摩肩接踵"];
for (var i = 0; i < str[0].length; i++) {
setElement("p", "------" + str[0].charAt(i) + "------");
//里面那层第一次循环完毕后,i==str[1]的长度-1,覆盖外层循环,导致外层循环条件为false,于是外层循环只执行一次。
for (var i = 0; i < str[1].length; i++) {
setElement("p", str[1].charAt(i));//contents += str.charAt(i);//var声明的i互相干架。
}
}
}
改为let声明后正常。
解构数组,构造数组。
//数组的解构
let input = [1, 2];
let [first, second] = input;//相当于使用索引声明两个变量first = input[0];second = input[1];
setElement("h1","数组的解构");
setElement("p",first+"----"+second);
//交换值
[second,first] = [first,second];
setElement("p",first+"----"+second);
//...的形式声明剩余变量。
let [o,,u,...t] = [1,2,3,4,5];//一些元素可以不必命名
setElement("p",o+"----"+u+"----"+t);
类似数组的解构。JavaScript对象就是json。
let abc = {a: "geek", b: 12, c: "fanr"}//符号:在此处的作用不是声明类型,而是声明属性的值。
let {a,b} = abc;//abc的属性更多
type C = { a: string, b?: number };//符号?:表示声明一个可选的属性
function f({ a, b }: C): void {//....}
了解即可,在声明中展开一个数组的值构成一个新的数组:
let num_a = [1,2,3];
let num_b = [...num_a,4,5,"hao"];//使用“...数组”展开为元组
let num_c = [num_a,4,5,"hao"];//展开
setElement("h1","展开数组")
setElement("p",num_b);
了解即可,在声明中展开一个对象的值构成一个新的数组:
let dog = {id:1,name:"dog"};
let home = {father:"da",monther:"mo",me:"hao",...dog,name:"狗狗阿里"};//使用"...对象"写法展开。后声明的属性允许覆盖
setElement("h1","展开对象");
setElement("p",home.name);
更多请参考:ts官方解释
要点:需要基本掌握
关系 | 关键字 |
---|---|
Voice | interface |
Animal -> Voice | abstract , class , implement |
Dog -> Animal | class , extend |
Cat -> Animal | class , extend |
Home | class |
ICFMoreH.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>接口、类、函数的定义和一些使用形式title>
<script src="ICFMore.js">script>
head>
<body>
<input type="button" value="千年京巴" onclick="jingbaClick()"/>
<p>p>
<p>
输入日期:
<input id="month-day" type="text" value=""/>
<button onclick="okClick()">确定button>
p>
body>
html>
ICFMore.ts
/**
* 接口、类、函数的定义和一些使用形式
*/
//声音接口
interface Voice {
getLanguage():string;//默认public
speak(content:any):void;
}
abstract class Animal implements Voice{
getLanguage(): string{
return "动物世界通行语";
}
abstract speak(content?: any): void;//可选参数。可选声明的形式为“修饰符 名称?:类型”
}
class Dog extends Animal{//private和protected不能出现在模块或命名空间元素上。此处不允许用来修饰类
// constructor(public name?:string,public id:string,public age:number,public sex:string){//可选参数不允许在固定参数之前
// super();
// }
//此处使用public,为this.xx = xx的简写。会自动创建并赋值属性
constructor(public id:string,public age:number,public sex:string,public name?:string){//不允许多个构造函数实现。。。
super();
}
speak(content: any): void {
alert(content);
}
getLanguage(): string{
return "汪星语";
}
}
class Cat extends Animal{
private _name: string;
speak(content?: any): void {
alert("喵喵!");
}
//getter,setter存取器
set name(name :string){
this._name = name;
}
get name():string{
return this._name;
}
}
class Home{
// let dogB:Dog = new Dog("001",4,"雌","go");//不能在此使用let,var声明
private catA:Cat = new Cat();
private dogA:Dog = new Dog("001",4,"雌","go");
private readonly tag?:string = "山顶洞人的home";//可选的、只读属性的home。可选声明的形式为“修饰符 名称?:类型”
protected go(){
}
play(monthDay:any){//默认public
this.catA.name="我是一只喵";//需要使用this.属性来访问,直接访问不到
this.dogA.name = "我是一只汪";
console.log(monthDay);
monthDay = parseInt(monthDay,10);//字符串转成十进制数字
let select = monthDay % 2;
switch (select){
case 0:
alert("Today,我 play with "+this.dogA.name);
break;
case 1:
alert("Today,我 play with "+this.catA.name);
break;
default:
alert("未知日期,我 play with "+this.dogA.name);
break;
}
}
}
//北京哈巴
function jingbaClick(){
let jingba:Dog = new Dog("京巴001",4,"雌");
jingba.speak("汪汪!");
}
function okClick(){
let home: Home = new Home();
let day = ( document.getElementById("month-day")).value;//HTMLElement中没有value属性。需要类型断言(强转)
// let day = (document.getElementById("month-day") as HTMLInputElement).value;//;类型断言的另一种方式。
home.play(day);
}
for…of 和 for…in:
具体区别:
let list = [4, 5, 6];
for (let i in list) {
console.log(i); // "0", "1", "2",索引
}
for (let i of list) {
console.log(i); // "4", "5", "6",值
}
//普通写法
for (let i = 0; i < list.length; i++) {
let num = list[i];
console.log(num);// "4", "5", "6",值
}
1.do…while和while
具体区别:
let list = [1,2,3,4,5];
//箭头函数表达式。能够在函数创建时绑定this,避免一些问题。常规写法则是咋函数调用时绑定,这时的this可能并非预期。
let wheel_do = ()=>{
let i =0;
do {
// console.log(list[i]);
htmlLog(list[i]);
i++;//先执行了do块的代码
}while (ilet wheel = () => { //简单来说就是解决this指向不明的问题。
let i = 0;
while (i < list.length) {
htmlLog(list[i]);
i++;
}
}
let htmlLog = function (text:any) {
let e = document.createElement("p");
e.textContent = text;
document.body.appendChild(e);
}
// wheel_do();
wheel();
ts中函数像其他值一样可以当成参数传来传去。箭头函数可用来定义匿名函数:
对数组中所有元素进行求和操作
var result = [1, 2, 3]
.reduce((total, current) => total + current, 0);
console.log(result);
代替TypeScript里默认的原型方法,你可以使用一个实例箭头函数来定义类成员:
class MyClass {
private status = "blah";
public run = () => { // <-- note syntax here
alert(this.status);
}
}
var x = new MyClass();
$(document).ready(x.run); // SAFE, 'run' will always have correct 'this'
常用,需要掌握
关键字:
导入与导出涉及模块,需要有加载器才能运行起来。比如服务于Node.js的CommonJS和服务于Web应用的Require.js。
模块:
导出的方式
1. 声明时直接导出
export let goHome :string = "go home";
export interface Hot{
//...
}
2. 使用export{}语句导出
interface Hot{
//...
}
export{Hot};
//export{Hot as HotDog};//Hot作为HotDog导出,重命名。as在类型断言也有相似用法。
HotHome.ts
export let dog = "热狗";
export interface Hot{
eat();
}
DogHome.ts
export class Dog{
eat(){
alert("eat ");
}
}
export {dog as nimaDog} from “./HotHome”;//从HotHome模块中导出dog,重命名为尼玛dog
导出之后使用import使用它:
TestHotDog.ts
import {nimaDog as nimashou} from "./DogHome";//从DogHome模块中导入nimadog,重命名为尼玛兽
class Test{
go(){
alert(nimashou);
}
}
多个模块一起导出:
语法:export * from "module"
示例:
export * from "./HotHome";
export * from "./DogHome";
4.默认导出
使用默认导出:
JQuery.d.ts
declare let $: JQuery;
export default $;
导入:
App.ts
import $ from "JQuery";
$("button.continue").html( "Next Step..." );
导入的方式
导入的方式和导出类似
1.直接导入声明
import {Coffee} from "./CoffeeHome"; //从CoffeeHome模块导入export声明的Coffee接口
2.导入声明并重命名
import {cat as Persiancat} from "./CoffeeHome";` //从CoffeeHome模块导入export声明的cat,重命名为Persian cat
3.所有export声明全部导入
import * as temp from "./CoffeHome";//从CoffeHome模块导入所有的export声明,命名为,使用时通过x调用。
let catty = temp.Persiancat;
4.具有副作用的导入
官方文档这么描述:
尽管不推荐这么做,一些模块会设置一些全局状态供其它模块使用。 这些模块可能 没有任何的导出或用户根本就不关注它的导出。 使用下面的方法来导入这类模块:
import "./my-module.js";
导入与导出综合示例:
使用export关键字导出写好的模块:
Email.ts
export class Email {
public static dress:string;
public static content:string;
sendTo(dress:string,content:string){
console.log("/n寄往:"+dress + "/n内容:"+content);
Email.dress = dress;
Email.content = content;
}
received(){
console.log("/n收到:"+Email.dress+"/n内容:"+Email.content);
return {d:Email.dress,c:Email.content};
}
}
使用import关键字导入Email模块,并使用它:
Biaoju.ts
import { Email } from "./Email";
/**
* 镖局
*/
export class Biaoju {
/**
* 押镖:货物
* 押镖时要发邮件通知委托人
*/
yabiao(huowu:string){
let email :Email = new Email();
email.sendTo("北京","我们今天开始押镖。"+Date.now());
console.log("押镖:"+huowu);
}
}
Jiefei.ts
import {Email as Feigechuanshu} from "./Email";//导入Email模块,重命名为飞鸽传书
/**
* 劫匪
*/
export class Jiefei{
/**
* 收到邮件之后,开始打劫
*/
dajie(){
let feige:Feigechuanshu = new Feigechuanshu();
let xin:{d:string,c:string} = feige.received();//收到信
console.log("收到飞鸽传书,来自:"+xin.d+"内容:"+xin.c);
alert(`${shanzhai},呔,留下买路财!`);
}
}
export let shanzhai = "劫机山寨";
继续引入模块,将劫匪和镖局模块引入:
testGo.ts
import {Biaoju} from "./Biaoju";
import {Jiefei} from "./Jiefei";
let biaoju_A = new Biaoju();
let jiefei_shanzaiA = new Jiefei();
biaoju_A.yabiao("百年大萝卜");
jiefei_shanzaiA.dajie();
TypeScript使用module声明模块,就能够直接跑了。
Geek.ts
module Geek{
export class Geek{
speak(){
alert("I'm a Geek. You're a Geek. Let's Geek out.");
}
}
}
调用模块:
TestGeek.ts
let geekfanr = new Geek.Geek();
geekfanr.speak();
使用时,要引入所有编译的JavaScript文件:
TestGeekH.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>极客title>
head>
<body>
<script src="Tugeek.js">script>
<script src="TestGeek.js">script>
body>
html>
运行,弹出一个“I’m a Geek. You’re a Geek. Let’s Geek out.”对话框。
TypeScript中文网
明月依稀 ,《TypeScript迅速入门与应该知道》
月飞鱼,《TypeScript 从入门到放弃》