迈向angularjs2系列(1):typescript指南
目录
1.typescript和javascript的区别
2.安装和helloworld程序
3.从ES6、7引入的新特性
4.卓越的静态类型
5.编写泛型代码
6.使用typings定义外部类型
源代码下载
https://pan.baidu.com/s/1eSeqWeQ,提取密码qygu。
前言
typescript是angularjs2推荐使用的脚本语言。它由微软2012年首次发布。
一. typescript和javascript的区别
1.从遵循的规范上的角度:
Javascript遵循ECMA5的规范,TypeScript是语法上对ECMA6的实现。
2.从功能上说:
TypeScript提供了类、模块和接口来帮助构建组件,更方便写面向对象的程序,所以被称为更好的typescript。
3.从支持上说:
所有的浏览器都支持ES5及之前的javascript,而没有浏览器支持typescript,所以需要编译。另外typescript支持所有javascript的语法。
照片显示了ES5、ES2015、ES2016以及typescript的关系。
二. typescript的安装和helloworld程序
(1)npm安装
npm install -g typescript@1.8 全局安装了1.8版本的typescript编译器和tsc可执行程序(稍后就能看到使用tsc命令转换ts文件了),并且添加到环境变量中。为了确认正常,打印-v命令。
$ npm -v //首先看一下npm是不是新版本
$ npm install -g typescript@1.8. //全局安装typescript
$ tsc -v
显示typescript的版本是:
(2)运行第一个ts程序。
第一种方式。
首先在1.hello.ts程序中输入:
console.log("hello world!")
然后执行命令:
$ tsc 1.hello.ts //把ts文件转换为等价的hello.js
最后运行node来执行js文件。
$ node 1.hello.js //打印出hello world。成功!
第二种方式。
好处是运行一个命令就把转换和执行的任务完成了。
先装好typescript和ts-node.
$ npm install typescript@1.8 -g //装好ts
$ npm install -g ts-node //装ts-node模块,选项是-g哦。
再运行命令执行文件。
$ ts-node 1.hello.ts //打印hello world,成功!
三. 从ES6、7引入的新特性
ES2015和ES2016有比较大的变化。
(1)ES2015的箭头函数
由来:javascript有一级函数的特性,也就是说,函数能够当做参数进行传参,很好的用法不过太啰嗦,所以ES2015提供了箭头函数,更加简洁。
ts例子1:
var even=[3,1,56,7].filter(el=>!(el%2));
//!(el%2)偶数的取模为0,取反为true,那么filter函数就说,恭喜,通过了!没被通过的,被无情抛弃
console.log(even);
//打印56咯。
通过运行ts-node命令,屏幕显示结果为:
ts例子2:
先预热一下,reduce函数是ES5的数组方法,第一个参数是回调callback,第二个参数是初始值。这里的代码第一个参数是一个箭头函数,和我们平常写的function没有本质区别。第二个参数是初始值0.
var result=[1,2,3]
.reduce((total,current)=>total+current,0);
//reduce遍历数组,返回值是total+current。
//回调函数的参数是total和current,total是上一次的返回值,第一次就为初始值0.
// current是当前数组元素的值。 //那么就清晰了,第一个total为0,当前元素是1,返回的0+1.
console.log(result);
通过运行ts-node命令,屏幕显示结果为:
ts例子3:
sort是经典的排序函数。基本思路是先对价格排序,如果价格相等,再对数量排序。
var data=[
{price:10,total:70},
{price:94,total:340},
{price:14,total:34},
{price:14,total:12}
];
//
var sorted=data.sort((a,b)=>{
//a、b为依次遍历的数组元素
var diff=a.price-b.price;
if(diff!==0){
return diff;
}
return a.total-b.total;
//返回值小于0,a比b小,排在前端。返回值大于0,a比b大,排在后面
})
console.log(sorted);
通过运行ts-node命令(编译),屏幕显示正确的排序结果为:
ts例子4:
function MyComponent(){
this.age=42;
console.log(this);
setTimeout(()=>{
//箭头函数的特性,this对象依然是外部this指向,并不会被改变。
this.age+=1;
console.log(this.age);
},100);
//等待100ms,age加1等于43,并打印出来
}
new MyComponent();
通过编译,屏幕显示:
(2)ES2015和ES2016中的类
首先说明一下,ES6就是ES2015。ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。
然后ECMAScript 2016就是ES7。
ES6的类依然是使用构造函数和基于原型的继承,但是语法更加方便和简洁。
下面是ES2016定义类的语法:
class Human{
static totalPeople=0;
_name;//ES2016的属性定义语法
constructor(name){
this._name=name;
Human.totalPeople+=1;
}
get name(){
return this._name;
}
set name(val){
this._name=val;
}
//name属性的get和set方法
talk(){
return "Hi,I'm"+this.name;
}
}
class Developer extends Human{
_languages;//ES2016的属性语法
constructor(name,languages){
super(name);
this._languages=languages;
}
get languages(){
return this._languages;
}
talk(){
return super.talk()+" And I Know "+this.languages.join('.'); }
}
var human=new Human("foobar");
var dev=new Developer("bar",["javascript"]);
console.log(dev.talk());
喜欢!除了类的定义体是对象外,属性和方法的书写和java很像,我喜欢的方式。
通过编译,屏幕显示结果为:
(3)定义块级作用域中可见的变量
java和c++是块级作用域。
只列举代码,表现为2点,第一个是特定代码块的变量只能代码块内部可见,第二,嵌套在内部的代码块中也可见。
public class Demo{
// 属性块,在类初始化属性时候运行
{
int j = 2;// 块级变量
} public void test1() {
int j = 3; // 方法级变量
if(j == 3) {
//j变量在代码嵌套的内部if语句中可见
int k = 5; // 块级变量
}
}
javascript是函数作用域。
var fns=[];
for(var i=0;i<5;i+=1){
fns.push(function(){
console.log(i);
})
}
fns.forEach(fn=>fn());
打印结果,很奇怪。
ES6代码:
var fns=[];
for(let i=0;i<5;i+=1){
fns.push(function(){
console.log(i);
})
}
fns.forEach(fn=>fn());
打印结果:
(4)使用ES2016装饰器进行元编程。
装饰器是ES2016的一个提案,它的依据是“在设计阶段可以对类和属性进行注释和修改”。在angular2很常用,可用来定义组件、指令以及管道,并且还能配合依赖注入机制来使用。
首先,装饰器能干吗。
装饰器典型的用法是把方法和属性标记为过期,另一个应用场景是声明式语法,从而实现面向切面的编程。其实呢,装饰器只是一个语法糖而已。装饰器目前并没有得到真正的使用。
Experimental support for decorators is a feature that is subject to change in a future release.
//编写了Person类,它只有一个getter,名字为kidCount
class Person{
//kidCount有一个装饰器nonenumerable
@nonenumerable
get kidCount(){
return 42;
}
}
//装饰器函数接收3个参数,最后返回descriptor属性。
function nonenumerable(target,name,descriptor){
descriptor.enumerable=false;
//可枚举性
return descriptor;
}
var person=new Person();
for(let prop in person){
console.log(prop);
}
这个代码只是做演示,因为typescript并不能编译它。
对应的ES5语法类似于:
descriptor=nonenumerable(Person.prototype,'kidCount',descriptor);
//descriptor
Object.defineProperty(Person.prototype,'kidCount',descriptor);
接下来,介绍angular 2装饰器的用法。
@Component({
selector:"app",
providers:[NameList],
tempalteUrl:"./app.html",
directives:[RouterOutlet,RouterLink]
});
//这个定义好拽呀,直接写好@+Component+选项对象
@RouterConfig({
{path:"/",component:Home,name:'home'},
{path:"/",component:About,name:'about'}
});
//写好@+RouterConfig+选项对象
export class App{}
这个代码现在还不能运行,等到使用angular2的时候就清楚明了了。
(5)使用ES2015编写模块化的代码
angular 1.x引入了一套模块系统,不过并不支持懒加载特性。angular 2种充分利用了ES2015提供的模块系统。ES2015提供了声明式API,以及使用模块加载器的命令式API。
语法分为export和import两个方面。
第一,看一个简单的DEMO:
math.ts:
export function square(x){
return Math.pow(x,2);
}
export function log(x){
return Math.log(x);
}
export const PI=Math.PI;
math2.ts,更简洁的写法而已:
function square(x){
return Math.pow(x,2);
}
function log(x){
return Math.log(x);
}
const PI=Math.PI;
export {square,log,PI}
app.ts调用,要编译的是app.ts哦:
import {square,log} from "./math";
console.log(square(2));
console.log(log(100));
屏幕显示效果:
第二,ES2015模块化语法带有隐式的异步行为。
比如说,
A模块依赖于B、C模块。当用户请求A模块,JS模块加载器会先加载B和C模块,才能调用A模块。这里B和C模块都是异步加载的。
第三,典型的应用场景会给导出的内容起一个名字。
使用别名导入整个模块的DEMO:
import * as math from "./math";
//as语法咯
console.log(math.square(2));
console.log(math.log(100));
第四,默认导出。
模块导出使用了export default语法,是一种带名字的导出。
基本的默认导出DEMO:
math3.ts:
export default function cube(x){
return Math.pow(x,3);
//默认导出的名字是cube
}
export function square(x){
return Math.pow(x,2);
}
app3.ts:
import cube from "./math3";
//等同于import {default as cube} from "./math3
console.log(cube(3));
显示结果正常:
默认导出混合其他导出的DEMO:
math3.ts:
export default function cube(x){
return Math.pow(x,3);
//默认导出的名字是cube
}
export function square(x){
return Math.pow(x,2);
}
import cube,{square} from "./math3";
console.log(square(2));
console.log(cube(3));
显示结果OK:
(6)ES2015的模块加载器
通过编程的方式加载app模块执行main函数,使用System对象的import方法就好了。现在代码因为缺乏配置项,所以还运行不起来。
app.ts:
export function main(){
console.log(2);
}
init.js
System.import("./app")
.then(app=>{
app.main();
})
.catch(error=>{
console.log("致命的错误");
});
四: 卓越的静态类型
有了静态类型,那么IDE开发环境除了避免输入错误的语法高亮,还提供精确静态分析的建议。很棒。
typescript的所有类型包含几类:
● 原生类型
● any类型
● Object类型
●类
●接口
● 泛型
(1)原生类型
就是javascript比较熟悉的Number、String、Boolean、Null、以及Undefined。
除了webstorm报类型(type)错误,运行编译命令,typescript 也报错 Type 'string' is not assignable to type 'number' 。那么就是说,一旦foo设置了类型,就不能赋值为其他类型了。
而Enum是用户自定义的原生类型,它是Number的子类。含义是枚举用户自定义的类型,由一系列有名称的值也就是元素构成。
定义enum如下:
enum STATES{
CONNECTING,
WAITING,
CONNECTED
}
//定义枚举类型
if(this.state==STATES.CONNECTING){
//通过点语法引入
}
(2)any类型
any类型是所有其他类型的父类,代表可以拥有任何类型的值,类似于动态类型,一方面不会报错,另一方面则放弃了typescript的优点了。
let foo:any;
foo={};
foo="bar";
foo+=24;
console.log(foo);//结果为"bar 24"。
(3)Object类型
第一,普通的对象都是Object类型。
第二,Object类型的子类是Array类型。
Typescript的数组,要求元素类型相同。都可以使用js的各种数组方法,比如push、join、splice等,也可以使用方括号运算符对数组元素进行访问。
数值型数组DEMO:
let primes:number[]=[];
primes.push(2);
primes.push(3);
console.log(primes);
any型数组:
let randomItems:any[]=[];
randomItems.push(1);
randomItems.push("foo");
randomItems.push("{}");
console.log(randomItems);
屏幕结果为
第三,Object类型的子类是Function类型。
javascript有两种方式创建新函数:
//函数表达式
var isPrime=function(n){ }
//函数声明
function isPrime(n){ }
//或者,使用箭头函数
var isPrime=n=>{
//函数体
}
Typescript增加的是参数和返回值的类型。
函数表达式:
let isPrime:(n:number)=>boolean=n=>{
//整个函数赋给变量isPrime,参数是number类型的n,返回值是boolean类型的n,函数体在{}里面
}
函数声明:
function isPrime(n:number):boolean{
//参数为number类型,返回值为boolean类型
}
对象字面量的定义写法:
let person={
_name:null,
setName(name:string):void{
//参数是string类型,返回值是void
this._name=name;
}
}
(4)类
typescript定义类,属性的声明式强类型的。
class-basic.ts:
class Human {
static totalPeople=0;
_name:string;//强类型的哦
constructor(name){
this._name=name;
Human.totalPeople+=1;
};
get name(){
return this.name;
}
set name(val){
this._name=val;
}
talk(){
return "HI,I'am"+this._name;
}
}
let human=new Human("foo");
console.log(human._name);
打印结果为
成功!
访问修饰符有3个。更好的实现封装和更优雅的接口。
●public。public的属性和方法在任何地方可以访问。
●private。private的属性和方法只能在类定义内部进行访问。
●protected。protected的属性和方法可以类定义内部访问,也可以从子类访问。
//typescript实现
class Human{
static totalPeople=0;
constructor(protected name:string,private age:number){
//定義了一個protected型的屬性,名為name,類型為string
//age屬性。好處是避免显示式的赋值操作
Human.totalPeople+=1;
}
talk(){
return "Hi,I'm"+this.name;
}
}
class Developer extends Human{
constructor(name:string,private languages:string[],age:number){
//显式使用访问修饰符,或者定义接收的参数类型,都可以混合使用的。
super(name,age);
}
talk(){
return super.talk()+" And I Know "+this.languages.join('.'); }
}
//创建developer类的一个新实例
let Dev=new Developer("foo",["javascript","Go"],42);
//dev.languages=["java"];这行代码会报一个私有属性的错误
let human=new Human("foo",42);
//human.age=42;由于私有属性,所以报错
//human.name="bar",会报一个protected错误。它只能在类类内部或者子类中访问
(5)接口
接口定义了一组对象共同的属性和方法,称作接口签名。要实现接口,那么实现定义接口规定的所有属性和方法。
关键字就2个,interface和implements。
interface Accountable1{
goIncome():number;
accountNumber:string
}
class Value implements Accountable1{
constructor( public accountNumber:string){
this.accountNumber=accountNumber;
}
goIncome():number{
return 100;
}
}
var extra=new Value("余额");
console.log(extra.accountNumber);
打印为
接口实现,成功!
接口继承
接口之间可以互相继承。接口继承另外一个接口,使用extends关键字。
interface-extends.ts:
interface Accountable2{
accountNumber:string;
getIncome():number;
}
interface Individual extends Accountable2{
ssn:string;
}
实现多个接口:
interface People{
age:number;
name:string;
}
interface Accountable{
accountNumber:string;
goIncome():number
}
class Person implements People,Accountable{
//实现多个接口,用逗号分隔
age:number;
name:string;
accountNumber:string;
constructor(age:number,name:string,accountNumber:string){ }
goIncome():number{
return 10;
}
}
var person=new Person(10,"100","1000");
五:编写泛型代码
可以写类似java的泛型代码,好精彩!使用“<T>”。能写出更简洁的代码来。
(1)使用泛型类
定义一组类型的class。
class Nodes<T> {
value:T;
left:Nodes<T>;
right:Nodes<T>;
}
let numberNode=new Nodes<number>(); let stringNode=new Nodes<string>(); numberNode.right=new Nodes<number>();//类型匹配
numberNode.value=42;//类型匹配
//numberNode.value="42";报错,类型不匹配
//numberNode.left=stringNode;报错,类型不匹配
(2)使用泛型函数
定义一组类型的函数。
function identify<T>(arg:T){
return arg;
}
interface Comparable{
compare(a:Comparable):number;
}
function sort<I extends Comparable>(arr:Comparable[]){
//
}
(3)多重泛型
class Pair<K,V>{
key:K;
value:V;
}
let pair=new Pair<string,number>()
pair.key="foo";
pair.value=42;
好精彩!
五: 使用typescript的类型推断机制简化代码
typescript可以猜测代码中的静态类型。好智能哦,所以可以用来省略一些代码。
let answer=42;
answer="42";
//会提示错误,因为一开始的赋值,typescript已经把它当做number类型了。
let answer;
answer=42;
answer="42";
//这个时候不会报错,因为第一次声明时,typescript给到的静态类型是any。
(1)最常见的类型
let x=["42",42];
//x的类型推断为any[]数组。
let x=[42.null,32];
//typescript的类型推断为number[]。
(2)与上下文有关的类型推断
这里可以看到e并没有规定类型,可是typescript就根据上下文推断它为MouseEvent鼠标事件。
六: 额外的类型定义
尽管静态类型很酷,但是我们使用的大部分前端类库都是基于javascript构建的,都是动态类型。而typescript提供了额外的类型定义,来给编译器提供提示。
(1)使用预定义的外部类型定义
step1:安装typings工具
npm install -g typings
于是就安装好了typings目录,tsconfig.json、typings.json中,内容为:
//tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true
},
"exclude": [
"node_modules"
]
}
//typings.json
{
"dependencies": {}
}
step2:创建基础配置
typings init
step3:搜索
$ typings search module
step4:安装is-builtin-module
$ typings install is-builtin-module --save
这个时候,typings.json的内容变为
{
"dependencies": {
"is-builtin-module": "registry:npm/is-builtin-module#1.0.0+20161031191623"
}
}
typings目录变为
(2)自定义外部类型
step1:定义好类库的接口。
define-external-type.ts:
interface LibraryInterface{
selectElements(selector:string):HTMLElement[];
hide(element:HTMLElement):void;
show(element:HTMLElement):void;
}
step2:定义ts.d文件。
interface DOMLibraryInterface{
selectElements(selector:string):HTMLElement[];
hide(element:HTMLElement):void;
show(element:HTMLElement):void;
}
declare var DOM:DOMLibraryInterface;
step3:DOM通过reference引入,编译器就会找到对应的外部类型定义了。
///<reference path="dom.d.ts" />
var DOM={
selectElements:function(selector:string):HTMLElement[]{
return [];
},
hide:function(element:HTMLElement):void {
element.hidden=true;
}
};
这个时候,会报错。直到完全实现定义的接口为止,如下:
///<reference path="dom.d.ts" />
var DOM={
selectElements:function(selector:string):HTMLElement[]{
return [];
},
hide:function(element:HTMLElement):void {
element.hidden=true;
},
show:function(element:HTMLElement):void{
element.hidden=false;
}
};
这样分离出来,就可以把全部的外部类型定义放在同一个文件里,方便管理了。
迈向angularjs2系列(1):typescript指南的更多相关文章
- 迈向angularjs2系列(8):angular cli和angular2种子项目
文章目录 1.angular cli快速搭建项目 2.angular2-seed 3.手动配置 题外话:如何更好的阅读本篇文章 一: angular cli的安装 Angular-cli(命令行界面, ...
- 迈向angularjs2系列(6):路由机制
目录1.angular-seed的路由2.路由机制的探索3.懒加载 一:angular-seed的路由 step1:安装种子项目 $ git clone --depth 1 https://gi ...
- 迈向angularjs2系列(5):依赖注入
一: 为什么要依赖注入 1.构造器引入依赖 假设一个类Car类依赖于Engine(引擎)类.Transition(变速箱)类,可使用构造器来完成. //类似如下代码 class Engine{} cl ...
- 迈向angularjs2系列(2):angular2指令详解
一:angular2 helloworld! 为了简单快速的运行一个ng2的app,那么通过script引入预先编译好的angular2版本和页面的基本框架. index.html: <!DOC ...
- 迈向angularjs2系列(7):表单
目录 一:校验表单的使用 1.搭建脚手架 2.校验表单的使用 3.select下拉列表的用法 一: 校验表单的使用 对于CRUD型的应用,表单是必备组件. 1.搭建脚手架 git clone http ...
- 迈向angularjs2系列(4):脏值检测机制
目录 一: 概念简介 脏值检测,简单的说就是在MVC的构架中,视图会通过模型的change事件来更新自己. 脏值检测的核心代码是观察者模式的实现,其机制会执行digest循环,在特定UI组件的上下文执 ...
- 迈向angularjs2系列(3):组件详解
一: 以组件开发一个to-do list应用 todo组件分为导入.接口定义.顶层组件.控制器.启动5个部分. app.ts: //导入 import {Component} from '@angul ...
- 寒武纪加速平台(MLU200系列) 摸鱼指南(二)--- 模型移植-环境搭建
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- 寒武纪加速平台(MLU200系列) 摸鱼指南(四)--- 边缘端实例程序分析
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
随机推荐
- 从零开始打jar包
经常会头疼于一个jar包是如何制作的,包括maven的打包方式,springboot的打jar包的原理,jar包稍稍有错误就会完全无法运行.在网上折腾了很久终于有些思路和步骤,在这里做个笔记 本文大纲 ...
- MySQL学习笔记(四):存储引擎的选择
一:几种常用存储引擎汇总表 二:如何选择 一句话:除非需要InnoDB 不具备的特性,并且没有其他办法替代,否则都应该优先考虑InnoDB:或者,不需要InnoDB的特性,并且其他的引擎更加合适当前情 ...
- 移动端https抓包那些事--初级篇
对于刚刚进入移动安全领域的安全研究人员或者安全爱好者,在对手机APP进行渗透测试的时候会发现一个很大的问题,就是无法抓取https的流量数据包,导致渗透测试无法继续进行下去. 这次给大家介绍一些手机端 ...
- helpers.bulk时 action_request_validation_exception 异常
语言Python 在开发时,批量插入ES,出现了action_request_validation_exception异常.我的代码是这样的 action = { } helpers.bulk(es, ...
- 关于canvas画布使用fillRect()时高度出现双倍效果解决办法
当设置canvas的宽度和高度时,只有内嵌css有效,外部css会出现拉伸的情况,例如: <!DOCTYPE html> <html lang="en"> ...
- 百度百科Tooltip的实现--原生js的应用
我们在浏览百度百科时,不难发现提示框的存在,如下图: 实现如下: 1.HTML代码部分 <!DOCTYPE html><html lang="en">< ...
- h5 录音
得益于前辈的分享,做了一个h5录音的demo.效果图如下: 点击开始录音会先弹出确认框: 首次确认允许后,再次录音不需要再确认,但如果用户点击禁止,则无法录音: 点击发送 将录音内容发送到对话框中.点 ...
- SpringBoot启动流程解析
写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...
- Spyder项目创建,打开与使用
1.Spyder项目的创建 新建一个Spyder项目需要点击Spyder上方标签栏中的Projects中的New Project 2.Spyder项目的打开 Spyder项目文件夹必须 存在.spyp ...
- 一次使用pywin32学到的知识
FindWindow这个函数检索处理顶级窗口的类名和窗口名称匹配指定的字符串.这个函数不搜索子窗口. FindWindowEx:FindWindowEx是在窗口列表中寻找与指定条件相符的第一个子窗口 ...