認(rèn)識(shí)TypeScript
TypeScript 和 JavaScript 聯(lián)系和區(qū)別踏志,當(dāng)時(shí)讀到一篇文章,覺(jué)得很有意思胀瞪。關(guān)鍵內(nèi)容摘抄一下针余。
文章中的觀點(diǎn)主要有,任意js都是合法的TypeScript凄诞,TypeScript 符合es6 標(biāo)準(zhǔn)圆雁,最關(guān)鍵還有強(qiáng)制類(lèi)型檢測(cè)。
interface Animal {
name: string;
age: number;
locality?: string; // 可選屬性
}
// 類(lèi)型定義時(shí)用interface 關(guān)鍵字帆谍, a: type; 的形式
// 與interface 主要用于數(shù)據(jù)結(jié)構(gòu)定義不同伪朽,class 主要用于定義類(lèi),業(yè)務(wù)邏輯
function f(x: Animal) {
return x.name;
}
var n:string = f({name: 'Benj', age: 3});
// typeScript 有函數(shù)缺省參數(shù)檢測(cè)
function createVM(os:string, version: number,
hasFloopy: bool =false,
FileName: string = hasFloopy? 'BOOT.ING': null {
setName(os + version.toString());
if (FileName) {
load(FileName);
}
}
// 完全長(zhǎng)得像C# 汛蝙。typescript有點(diǎn)像以C# 的方式來(lái)寫(xiě)JS烈涮,最終編譯為原生 JavaScript
// 并且上面這段代碼在編譯之后會(huì)變?yōu)閹?參數(shù)檢測(cè)的。undefined 表示有declare窖剑,但沒(méi)有賦值的變量
if (typeof hasFloopy === 'undefined') {
hasFloopy = false;
}
if (typeof FileName === 'undefinded') {
// ....
}
Arrow記號(hào)作為匿名函數(shù)的快捷方式坚洽,節(jié)省代碼,并且可以避免this指向的錯(cuò)誤西土。
// 和ES6類(lèi)似的Arrow. 使用回調(diào)函數(shù)的場(chǎng)合讶舰,容易犯錯(cuò)的是this的作用域。
var tickIncreaser = {
tick: 0,
increase: function() {
window.onclick = (e) => {
alert((this.tick++).toString());
}
}
}
// 以上Script經(jīng)過(guò)編譯后
//...
increase: function () {
// 將上下文環(huán)境保留在_this 變量中需了。
var _this = this;
window.onclick = function (e) {
alert((_this.tick++).toString))
}
}
//..
/* 構(gòu)造函數(shù) */
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 是立即執(zhí)行函數(shù), 等效于 var Human = (function(){...})() 這個(gè)在《JS設(shè)計(jì)模式和編程實(shí)踐》中有講到.
// TypeScript 符合ES6的標(biāo)準(zhǔn)跳昼,支持存取器。
get Salary(){
return salary;
}
h1.getSalary() // 可以獲取salary屬性
可以看到TypeScript 很類(lèi)似于靜態(tài)語(yǔ)言肋乍,有類(lèi)型檢測(cè)等特性庐舟。并且實(shí)現(xiàn)了ES6的許多特性,包括export住拭,class挪略,Arrow匿名函數(shù)等等历帚。實(shí)現(xiàn)了模塊化的管理方式,更加方便重構(gòu)(refactor).
參考資料 TypeScript:更好的JavaScript
Angular2.0
關(guān)于版本和核心組件
直到2016年8月杠娱,Angular2 還處于快速更新中挽牢,所以版本存在不穩(wěn)定。2016年8月最新版核心組件@angular/core的版本號(hào)是rc.5. 比上一版本新增了 ngModule 核心組件摊求,管理declaration等等禽拔。 并且@angular/router也有所更新,rc.1室叉,包含了RouteModule等關(guān)鍵組件睹栖。
根組件(app.component)和根模塊(app.module),一個(gè)web應(yīng)用至少需要一個(gè)根組件和一個(gè)根模塊。根組件包含路由茧痕,服務(wù)野来!在root層面注冊(cè)服務(wù)和路由singleton,使得子組件都可以用到同樣的服務(wù)和路由踪旷。
根模塊注冊(cè)了declaration曼氛,并導(dǎo)入了可選模塊:form, router 等等。
創(chuàng)建組件
關(guān)鍵要素令野,import 其他模塊舀患,裝飾器修飾當(dāng)前組件,定義組件的具體功能
import { Component } from '@angular/core';
@Component({
selector: '',
styles:,
templates:
})
export class yourComponent {
title=;
//...
}
根據(jù)單一職責(zé)原則 一個(gè)數(shù)據(jù)模型或者組件的職責(zé)應(yīng)該是單一的气破,這樣才可以實(shí)現(xiàn)非耦合聊浅,方便組件化。
創(chuàng)建一個(gè)自定義component需要 import现使,@Component裝飾器狗超,以及export class自定義組件。三個(gè)基本部分朴下。
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'>
`
})
多個(gè)組件之間的消息傳遞
其實(shí)原生的JavaScript 中可以通過(guò)全局變量或者函數(shù)調(diào)用的參數(shù)中來(lái)傳遞消息努咐,那么在Angular框架中這個(gè)問(wèn)題就演變?yōu)榱私M件之間的參數(shù)傳遞了。包括父組件和子組件殴胧,同級(jí)組件之間的參數(shù)傳遞渗稍。除了下文提到的@Input,@Injectable 這些方式团滥,還可以通過(guò)Angular中EventEmitter 類(lèi)來(lái)自定義事件竿屹,將某一組件中的事件發(fā)布給訂閱其消息的任意組件。詳細(xì)情況可以參考第二篇筆記灸姊。
@Input 裝飾目標(biāo)變量拱燃,表明這個(gè)變量的值由外部傳入
/* 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中注冊(cè) directive
@Component({
templates:`
<target [hero]='selectedHero'></target>
`
directives: [target組件類(lèi)名];
})
@Injectable 裝飾可注入的對(duì)象
// 整個(gè)服務(wù)是可用于注入的。
@Injectable()
export class HeroService {
getHeroes() {
return Promise.resolve(HEROES);
}
getHeroesSlowly() {
return new Promise<Hero[]>(resolve =>
setTimeout(() => resolve(HEROES), 2000)
);
}
}
// 在調(diào)用服務(wù)的組件@Component裝飾器中注冊(cè)providers
providers: [HeroService]
export class ** implements OnInit {
// 在構(gòu)造函數(shù)中實(shí)例化服務(wù)
constructor(private heroService: HeroService) {
}
getHeroes() {
this.heroService.getHeroes().then(heroes => {});
}
ngOnInit() {
this.getHeroes();
}
}
搭建Angular開(kāi)發(fā)環(huán)境
Angular開(kāi)發(fā)環(huán)境
創(chuàng)建項(xiàng)目文件夾力惯,定義包的依賴(lài)以及特別的項(xiàng)目設(shè)置
- package.json
- tsconfig.json (ts編譯器配置文件)
創(chuàng)建根組件(AppComponent),這個(gè)組件的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'
}
然后創(chuàng)建根模塊(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, 宿主頁(yè)面. 可用import導(dǎo)入模塊
<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') 實(shí)際上啟動(dòng)的是 main.js 中的命令碗誉,追溯到其中召嘶,其實(shí)執(zhí)行的是 bootstrap(HeroesComponent); 啟動(dòng)了整個(gè)應(yīng)用的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>
構(gòu)建并運(yùn)行應(yīng)用(因?yàn)閠ypescript可以開(kāi)啟watch transpile 模式弄跌,所以文件修改后自動(dòng)編譯為原生js,在頁(yè)面中可看到修改結(jié)果)
基于Phantomjs的Karma測(cè)試環(huán)境
由于phantomjs經(jīng)常安裝不上尝苇,則采用替換鏡像的方法铛只。
npm install phantomjs --registry=https://registry.npm.taobao.org