认识TypeScript
TypeScript 和 JavaScript 联系和区别,当时读到一篇文章,觉得很有意思。关键内容摘抄一下。
文章中的观点主要有,任意js都是合法的TypeScript,TypeScript 符合es6 标准,最关键还有强制类型检测。
interface Animal {
name: string;
age: number;
locality?: string; // 可选属性
}
// 类型定义时用interface 关键字, a: type; 的形式
// 与interface 主要用于数据结构定义不同,class 主要用于定义类,业务逻辑
function f(x: Animal) {
return x.name;
}
var n:string = f({name: 'Benj', age: 3});
// typeScript 有函数缺省参数检测
function createVM(os:string, version: number,
hasFloopy: bool =false,
FileName: string = hasFloopy? 'BOOT.ING': null {
setName(os + version.toString());
if (FileName) {
load(FileName);
}
}
// 完全长得像C# 。typescript有点像以C# 的方式来写JS,最终编译为原生 JavaScript
// 并且上面这段代码在编译之后会变为带 参数检测的。undefined 表示有declare,但没有赋值的变量
if (typeof hasFloopy === 'undefined') {
hasFloopy = false;
}
if (typeof FileName === 'undefinded') {
// ....
}
Arrow记号作为匿名函数的快捷方式,节省代码,并且可以避免this指向的错误。
// 和ES6类似的Arrow. 使用回调函数的场合,容易犯错的是this的作用域。
var tickIncreaser = {
tick: 0,
increase: function() {
window.onclick = (e) => {
alert((this.tick++).toString());
}
}
}
// 以上Script经过编译后
//...
increase: function () {
// 将上下文环境保留在_this 变量中。
var _this = this;
window.onclick = function (e) {
alert((_this.tick++).toString))
}
}
//..
/* 构造函数 */
class Human {
constructor(public name:string, public age:number){
static baseSalary = 1500;
static baseAge = 18;
}
printSalary(){
var salary = this.age < 18 ? 0: Human.baseSalary + this.age - (Human.baseAge) * 200;
alert('Salary of' + this.name + 'is ' + salary.toString());
}
}
var h1 = new Human('jack', 20);
var h2 = new Human('ross', 17);
h1.printSalary();
h2.printSalary();
// class 是立即执行函数, 等效于 var Human = (function(){...})() 这个在《JS设计模式和编程实践》中有讲到.
// TypeScript 符合ES6的标准,支持存取器。
get Salary(){
return salary;
}
h1.getSalary() // 可以获取salary属性
可以看到TypeScript 很类似于静态语言,有类型检测等特性。并且实现了ES6的许多特性,包括export,class,Arrow匿名函数等等。实现了模块化的管理方式,更加方便重构(refactor).
参考资料 TypeScript:更好的JavaScript
Angular2.0
关于版本和核心组件
直到2016年8月,Angular2 还处于快速更新中,所以版本存在不稳定。2016年8月最新版核心组件@angular/core的版本号是rc.5. 比上一版本新增了 ngModule 核心组件,管理declaration等等。 并且@angular/router也有所更新,rc.1,包含了RouteModule等关键组件。
根组件(app.component)和根模块(app.module),一个web应用至少需要一个根组件和一个根模块。根组件包含路由,服务!在root层面注册服务和路由singleton,使得子组件都可以用到同样的服务和路由。
根模块注册了declaration,并导入了可选模块:form, router 等等。
创建组件
关键要素,import 其他模块,装饰器修饰当前组件,定义组件的具体功能
import { Component } from '@angular/core';
@Component({
selector: '',
styles:,
templates:
})
export class yourComponent {
title=;
//...
}
根据单一职责原则 一个数据模型或者组件的职责应该是单一的,这样才可以实现非耦合,方便组件化。
创建一个自定义component需要 import,@Component装饰器,以及export class自定义组件。三个基本部分。
template synTax:
// onSelect() come from export function
// [(ngModel)]='selectedHero.name' two-way-binding.
// properties we used in the templates come from the exported component!
@Component({
templates:`
<li *ngFor='let hero of heroes'
[class.selected]='hero === selectedHero'
(click)='onSelect(hero)'
<div *ngIf='selectedHero'>
<input [(ngModel)]='selectedHero.name'>
`
})
多个组件之间的消息传递
其实原生的JavaScript 中可以通过全局变量或者函数调用的参数中来传递消息,那么在Angular框架中这个问题就演变为了组件之间的参数传递了。包括父组件和子组件,同级组件之间的参数传递。除了下文提到的@Input,@Injectable 这些方式,还可以通过Angular中EventEmitter 类来自定义事件,将某一组件中的事件发布给订阅其消息的任意组件。详细情况可以参考第二篇笔记。
@Input 装饰目标变量,表明这个变量的值由外部传入
/* use @Input to annotate the hero to be Input property.
* receive value from other Component.
*/
export class HeroDetailComponent {
@Input()
hero: Hero;
// present the property "hero" is type Hero;
}
// 在source组件中赋值
// 在source中注册 directive
@Component({
templates:`
<target [hero]='selectedHero'></target>
`
directives: [target组件类名];
})
@Injectable 装饰可注入的对象
// 整个服务是可用于注入的。
@Injectable()
export class HeroService {
getHeroes() {
return Promise.resolve(HEROES);
}
getHeroesSlowly() {
return new Promise<Hero[]>(resolve =>
setTimeout(() => resolve(HEROES), 2000)
);
}
}
// 在调用服务的组件@Component装饰器中注册providers
providers: [HeroService]
export class ** implements OnInit {
// 在构造函数中实例化服务
constructor(private heroService: HeroService) {
}
getHeroes() {
this.heroService.getHeroes().then(heroes => {});
}
ngOnInit() {
this.getHeroes();
}
}
搭建Angular开发环境
Angular开发环境
创建项目文件夹,定义包的依赖以及特别的项目设置
- package.json
- tsconfig.json (ts编译器配置文件)
创建根组件(AppComponent),这个组件的template中包含路由
// AppComponent.ts
@component{
template: `
<h1>{{title}}</h1>
<nav>
<a routerLink="/heroes" routerLinkActive="active" > Heroes </a>
<router-outlet></router-outlet>
`
}
export class AppComponent {
title: 'Tour of Angular2.0'
}
然后创建根模块(AppModule) 并且添加main.ts 配置组件信息
// update! since Angular2.0 stable, changed bootstrap function
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
添加index.html, 宿主页面. 可用import导入模块
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
<!-- When Angular calls the bootstrap function in main.ts,
it reads the AppComponent metadata, finds the my-app selector,
locates an element tag named my-app, and renders our application's
view between those tags. -->
</body>
</html>
// Systemjs.config.js
(function(global) {
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
'angular2-in-memory-web-api': {
main: './index.js',
defaultExtension: 'js'
}
}
})
在index.html中 import('app') 实际上启动的是 main.js 中的命令,追溯到其中,其实执行的是 bootstrap(HeroesComponent); 启动了整个应用的root组件!!
// 而在index.html中引入的systemjs.config.js中
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
<!-- 3. Display the application -->
<body>
<my-heroes>Loading...</my-heroes>
</body>
构建并运行应用(因为typescript可以开启watch transpile 模式,所以文件修改后自动编译为原生js,在页面中可看到修改结果)
基于Phantomjs的Karma测试环境
由于phantomjs经常安装不上,则采用替换镜像的方法。
npm install phantomjs --registry=https://registry.npm.taobao.org