目前前端發(fā)展得百花齊放冬竟、技術(shù)日新月異欧穴,就連各種編輯器也好用到匪夷所思,又層出不窮泵殴。近兩年來(lái)涮帘,我從Sublime Text,到Atom笑诅,到Brackets调缨,再到今天的VSCode疮鲫。從一開(kāi)始不斷玩各種插件配置軟件,到現(xiàn)在幾乎不怎么配置插件就能滿(mǎn)足到我的基本需求弦叶,編輯器軟件之間的競(jìng)爭(zhēng)也甚是激烈俊犯。
VSCode全稱(chēng)是Visual Studio Code, 是一款免費(fèi)開(kāi)源的現(xiàn)代化輕量級(jí)代碼編輯器伤哺,內(nèi)置JavaScript燕侠、TypeScript,支持 Node.js立莉、ES6绢彤、AngularJS、ReactJS等蜓耻,幾乎所有主流的開(kāi)發(fā)語(yǔ)言的語(yǔ)法高亮茫舶、智能代碼補(bǔ)全、自定義熱鍵刹淌、括號(hào)匹配饶氏、代碼片段、代碼對(duì)比 Diff有勾、GIT 等特性疹启,而且擁有豐富的插件生態(tài)系統(tǒng),可通過(guò)安裝插件來(lái)支持C++柠衅、C#、Python籍琳、PHP等其他語(yǔ)言菲宴,并針對(duì)網(wǎng)頁(yè)開(kāi)發(fā)和云端應(yīng)用開(kāi)發(fā)做了優(yōu)化∏骷保跨平臺(tái)支持Windows喝峦,OS X和Linux。運(yùn)行速度非常流暢呜达,不亞于Sublime Text谣蠢,打開(kāi)大文件甚至更有優(yōu)勢(shì)。VSCode和Atom查近、Brackets一樣眉踱,都屬于是Webkit類(lèi)的編輯器。
輕量級(jí)霜威、開(kāi)源谈喳、跨平臺(tái),聽(tīng)起來(lái)就不像是微軟能做出來(lái)的事戈泼。但猶如能生產(chǎn)出TypeScript一樣婿禽,現(xiàn)代的微軟也正在做很現(xiàn)代的事情赏僧,實(shí)在令人刮目相看。
由C#的首席架構(gòu)師安德斯·海爾斯伯格領(lǐng)銜開(kāi)發(fā)的TypeScript扭倾,是JavaScript的一個(gè)超集淀零,向JavaScript添加了可選的靜態(tài)類(lèi)型,強(qiáng)類(lèi)型膛壹,以及模塊系統(tǒng)和基于類(lèi)的面向?qū)ο缶幊碳葜小ypeScript是為大型應(yīng)用之開(kāi)發(fā)而設(shè)計(jì),而編譯時(shí)它產(chǎn)生 JavaScript 以確保兼容性恢筝。
按我的理解是哀卫,微軟希望你學(xué)會(huì)了C#以后,前端撬槽、后端此改、數(shù)據(jù)庫(kù)全部都能編寫(xiě)程序。
首先侄柔,我們先來(lái)了解一下在vscode如何安裝共啃、配置TypeScript。Visual Studio2015和Visual Studio 2013 Update 2默認(rèn)包含了TypeScript暂题。如果你沒(méi)有安裝包含TypeScript的Visual Studio 移剪,可以通過(guò)NPM進(jìn)行安裝:
npm install -g typescript
安裝完成以后,就可以在vscode中編寫(xiě)以及匯編ts文件了薪者。在vscode中匯編只需要在ts文件下纵苛,按著按shift+ctrl+b,會(huì)提示沒(méi)有配置文件言津,點(diǎn)擊配置后會(huì)自動(dòng)在根目錄生成一個(gè).vscode文件夾攻人,里面有個(gè)tasks.json文件,按默認(rèn)配置就可以悬槽。
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"args": ["-p", "."],
"showOutput": "silent",
"problemMatcher": "$tsc"
}
接著在根目錄里面怀吻,新建一個(gè)tsconfig.json的生成配置文件。
{
"compilerOptions": {
"target": "ES5",
"noImplicitAny": false,
"module": "amd",
"removeComments": false,
"sourceMap": true
}
}
以上初婆,配置ts文件已經(jīng)完成蓬坡。下面我們來(lái)建一個(gè)新類(lèi):class Duck
class Duck {
DuckName: string;
Age: number;
Fly: string;
constructor(duckName: string, age: number, fly: string) {
this.DuckName = duckName;
this.Age = age;
this.Fly = fly;
}
greet() {
let outString: string = "我是鴨子,我的名字是" + this.DuckName + "磅叛,我現(xiàn)在" + this.Age + "歲," + this.Fly;
console.log(outString);
}
}
var getduck = new Duck("黃鴨子", 1, "我會(huì)飛");
getduck.greet();//我是鴨子屑咳,我的名字是黃鴨子,我現(xiàn)在1歲,我會(huì)飛
接著我們遇到一個(gè)客戶(hù)弊琴,他要求把橡皮鴨也要加入我們的系統(tǒng)當(dāng)中乔宿。第一反應(yīng)就是,好吧访雪,我做一個(gè)繼承類(lèi)详瑞。
class Duck {
DuckName: string;
Age: number;
Fly: string;
constructor(duckName: string, age: number, fly: string) {
this.DuckName = duckName;
this.Age = age;
this.Fly = fly;
}
greet() {
let outString: string = "我是鴨子掂林,我的名字是" + this.DuckName + ",我現(xiàn)在" + this.Age + "歲," + this.Fly;
console.log(outString);
}
}
class RubberDuck extends Duck {
constructor(duckName: string, age: number, fly: string) {
super(duckName, age, fly);
}
greet() {
let outString: string = "我是橡皮鴨子坝橡,我的名字是" + this.DuckName + "泻帮,我現(xiàn)在" + this.Age + "歲," + this.Fly;
console.log(outString);
}
}
var getduck = new Duck("黃鴨子", 1, "我會(huì)飛");
var getrubberduck: Duck = new RubberDuck("小鴨子", 0, "我不會(huì)飛");
getduck.greet();//我是鴨子,我的名字是黃鴨子计寇,我現(xiàn)在1歲,我會(huì)飛
getrubberduck.greet();//我是橡皮鴨子锣杂,我的名字是小鴨子,我現(xiàn)在0歲,我不會(huì)飛
其實(shí)我們也可以使用get/set封裝番宁,而不用繼承元莫,就可以達(dá)到上面的目的。
class Duck {
DuckName: string;
Age: number;
Fly: string;
private _className: string;
constructor(duckName: string, age: number, fly: string) {
this.DuckName = duckName;
this.Age = age;
this.Fly = fly;
}
get className(): string {
return this._className;
}
set className(newname: string) {
this._className = newname;
let outString: string = "我是" + newname + "蝶押,我的名字是" + this.DuckName + "踱蠢,我現(xiàn)在" + this.Age + "歲," + this.Fly;
console.log(outString);
}
}
var getduck = new Duck("黃鴨子", 1, "我會(huì)飛");
getduck.className = "鴨子"; //我是鴨子,我的名字是黃鴨子棋电,我現(xiàn)在1歲,我會(huì)飛
var getduck = new Duck("小黃", 0, "我不會(huì)飛");
getduck.className = "橡皮鴨子"; //我是橡皮鴨子茎截,我的名字是小黃,我現(xiàn)在0歲,我不會(huì)飛
其實(shí)繼承類(lèi)的目的是在于繼承的同時(shí)進(jìn)行功能的擴(kuò)展赶盔。下面我們除了將鴨子的類(lèi)名加進(jìn)來(lái)企锌,還增加多一個(gè)rubbergreet()的方法:
class Duck {
DuckName: string;
Age: number;
Fly: string;
constructor(duckName: string, age: number, fly: string) {
this.DuckName = duckName;
this.Age = age;
this.Fly = fly;
}
greet() {
let outString: string = "我是鴨子,我的名字是" + this.DuckName + "于未,我現(xiàn)在" + this.Age + "歲," + this.Fly;
console.log(outString);
}
}
class getDuck extends Duck {
private classname:string;
constructor(duckName: string, age: number, fly: string,classname:string) {
super(duckName, age, fly);
this.classname=classname;
}
greet() {
let outString: string = "我是"+this.classname+"撕攒,我的名字是" + this.DuckName + ",我現(xiàn)在" + this.Age + "歲," + this.Fly;
console.log(outString);
}
rubbergreet(){
console.log("zzz,zzz");
}
}
var getduck = new Duck("黃鴨子", 1, "我會(huì)飛");
var getrubberduck= new getDuck("小鴨子", 0, "我不會(huì)飛","橡皮鴨子");
getduck.greet();//我是鴨子烘浦,我的名字是黃鴨子抖坪,我現(xiàn)在1歲,我會(huì)飛
getrubberduck.greet();//我是橡皮鴨子,我的名字是小鴨子谎倔,我現(xiàn)在0歲,我不會(huì)飛
getrubberduck.rubbergreet();//zzz,zzz
在類(lèi)名前加上abstract
說(shuō)明這個(gè)類(lèi)是抽象類(lèi),抽象類(lèi)只需要寫(xiě)出類(lèi)的定義,由實(shí)現(xiàn)類(lèi)完成它的具體細(xì)節(jié).
如果去實(shí)體化一個(gè)抽象類(lèi)柳击,將會(huì)產(chǎn)生一個(gè)錯(cuò)誤猿推。不信片习,你拿上面的Duck類(lèi)試試。
假設(shè)由于我們經(jīng)營(yíng)得當(dāng)蹬叭,系統(tǒng)需要升級(jí)藕咏。新來(lái)的工程師看了我們的代碼,叫了一聲:搞什么嘛秽五,這完全可以用接口孽查!
什么是接口呢?類(lèi)是對(duì)象的抽象坦喘,那么接口就是類(lèi)的抽象盲再。有一個(gè)編程原則是這樣子說(shuō)的:針對(duì)接口編程西设,而不是針對(duì)現(xiàn)實(shí)編程。
下面我們寫(xiě)一個(gè)簡(jiǎn)單的接口答朋,把鴨子的類(lèi)和接口先組合贷揽。
interface DuckConfig {
DuckName?: string;
Age?: number;
Fly?: string;
Duckclass?: string;
}
function createDuck(config:DuckConfig):{out:string;}
{
var newDuck={out:"我是"};
if (config.Duckclass){
newDuck.out+=config.Duckclass;
}
else{
newDuck.out+="鴨子";
}
if (config.DuckName){
newDuck.out+=",我的名字是"+config.DuckName;
}
if (config.Age){
newDuck.out+="梦碗,我今年"+config.Age+"歲";
}
if (config.Fly){
newDuck.out+="禽绪,"+config.Fly;
}
console.log(newDuck.out);
return newDuck;
}
var blackDuck = createDuck({DuckName:"小黑",Age:1,Fly:"我會(huì)飛",Duckclass: "黑鴨子"});//我是黑鴨子,我的名字是小黑洪规,我今年1歲印屁,我會(huì)飛
var blackDuck = createDuck({DuckName:"小黃",Age:1,Fly:"我不會(huì)飛"});//我是鴨子,我的名字是小黃斩例,我今年1歲雄人,我不會(huì)飛
var rubberDuck = createDuck({Duckclass: "橡皮鴨子"});//我是橡皮鴨子
這樣寫(xiě)挺規(guī)范的,這樣一來(lái)樱拴,我們來(lái)多少種鴨子都不怕了柠衍。我想看看js是怎么處理“接口”的,一看卻傻眼了:
function createDuck(config) {
var newDuck = { out: "我是" };
if (config.Duckclass) {
newDuck.out += config.Duckclass;
}
else {
newDuck.out += "鴨子";
}
if (config.DuckName) {
newDuck.out += "晶乔,我的名字是" + config.DuckName;
}
if (config.Age) {
newDuck.out += "珍坊,我今年" + config.Age + "歲";
}
if (config.Fly) {
newDuck.out += "," + config.Fly;
}
console.log(newDuck.out);
return newDuck;
}
var blackDuck = createDuck({ DuckName: "小黑", Age: 1, Fly: "我會(huì)飛", Duckclass: "黑鴨子" });
var blackDuck = createDuck({ DuckName: "小黃", Age: 1, Fly: "我不會(huì)飛" });
var rubberDuck = createDuck({ Duckclass: "橡皮鴨子" });
config就是一個(gè)對(duì)象正罢,什么接不接口的阵漏,煩不煩啊,JavaScript就是這么任性~~
我們的經(jīng)營(yíng)不斷拓展翻具,公司已經(jīng)有計(jì)劃的要引進(jìn)多種動(dòng)物履怯。我們現(xiàn)在需要若干個(gè)類(lèi)來(lái)管理各種動(dòng)物的叫聲,通過(guò)類(lèi)和接口相互約束裆泳,我們要寫(xiě)出擴(kuò)展性強(qiáng)叹洲、易于修改的代碼。
interface IBark{
bark();
}
class cat implements IBark{
bark(){
console.log("喵喵")
}
}
class dog implements IBark{
bark(){
console.log("旺旺")
}
}
var catbark=new cat();
catbark.bark();//喵喵
var dogbark=new dog();
dogbark.bark();//旺旺
下面的代碼就是匯編而成的JavaScript工禾,由于沒(méi)有接口的約束运提,.bark命名并沒(méi)有硬性規(guī)定,所以想寫(xiě)成什么都可以闻葵。在這種小代碼上當(dāng)然看不出什么問(wèn)題民泵,甚至還會(huì)覺(jué)得下面的代碼比較好理解。當(dāng)成一個(gè)大系統(tǒng)槽畔、當(dāng)要系統(tǒng)修改時(shí)問(wèn)題就不少了栈妆。
var cat = (function () {
function cat() {
}
cat.prototype.bark = function () {
console.log("喵喵");
};
return cat;
}());
var dog = (function () {
function dog() {
}
dog.prototype.bark = function () {
console.log("旺旺");
};
return dog;
}());
var catbark = new cat();
catbark.bark();
var dogbark = new dog();
dogbark.bark();
最后來(lái)說(shuō)說(shuō)模塊,TypeScript的模塊分為內(nèi)部模塊、外部模塊鳞尔。
TypeScript也有外部模塊的概念嬉橙。使用外部模塊的兩種情況:node.js 和require.js,這里不做介紹寥假。
下面說(shuō)說(shuō)內(nèi)部模塊憎夷,“內(nèi)部模塊”現(xiàn)在稱(chēng)做“命名空間”。 “外部模塊”現(xiàn)在則簡(jiǎn)稱(chēng)為“模塊”昧旨。TypeScript 1.5里術(shù)語(yǔ)名已經(jīng)發(fā)生了變化拾给。module X {} 相當(dāng)于現(xiàn)在推薦的寫(xiě)法 namespace X {}。
最后設(shè)計(jì)一個(gè)稍微難點(diǎn)的程序兔沃,將上面的知識(shí)點(diǎn)做一個(gè)總結(jié):
我們假設(shè)蒋得,產(chǎn)品越來(lái)越多,從供應(yīng)商那里取得產(chǎn)品的編碼乒疏。但是供應(yīng)商很亂额衙,有時(shí)提供6位數(shù)編碼,有時(shí)提供產(chǎn)品名稱(chēng)怕吴。我們就用了正則表達(dá)式進(jìn)行核對(duì)窍侧,如果是6位數(shù)字的,那么加入編碼的數(shù)組转绷,如果是單純字母名稱(chēng)的伟件,加入名稱(chēng)數(shù)組。如果混合的议经,我們就當(dāng)它是廢品斧账。
開(kāi)頭我們就用上了namespace Vcode,然后再立接口煞肾,接口將返回一個(gè)boolean咧织,以及一個(gè)寫(xiě)入數(shù)組的方法。
namespace Vcode {
export interface StringCode {
isAcceptable(s: string): boolean;
toarr(s);
} //接口
var nameRegexp = /^[A-Za-z]+$/;
var CodeRegexp = /^[0-9]+$/;
var namearr: string[] = [];
var codearr: string[] = [];
export class nameOnlyValidator implements StringCode {
isAcceptable(s: string) {
return nameRegexp.test(s);
}
toarr(s) {
namearr.push(s);
}
}
export class CodeValidator implements StringCode {
isAcceptable(s: string) {
return s.length === 6 && CodeRegexp.test(s);
}
toarr(s) {
codearr.push(s);
}
}
var strings: string[] = ['littDuck', '345633', 'No:177', 'alexzeng'];
var namestring = new Vcode.nameOnlyValidator();
var codestring = new Vcode.CodeValidator();
for (var i in strings) {
if (codestring.isAcceptable(strings[i])) {
codestring.toarr(strings[i]);
}
if (namestring.isAcceptable(strings[i])) {
namestring.toarr(strings[i]);
}
}
console.log(namearr);
console.log(codearr);
}
最終匯編成js文件:
var Vcode;
(function (Vcode) {
var nameRegexp = /^[A-Za-z]+$/;
var CodeRegexp = /^[0-9]+$/;
var namearr = [];
var codearr = [];
var nameOnlyValidator = (function () {
function nameOnlyValidator() {
}
nameOnlyValidator.prototype.isAcceptable = function (s) {
return nameRegexp.test(s);
};
nameOnlyValidator.prototype.toarr = function (s) {
namearr.push(s);
};
return nameOnlyValidator;
}());
Vcode.nameOnlyValidator = nameOnlyValidator;
var outarr = (function () {
function outarr() {
}
return outarr;
}());
Vcode.outarr = outarr;
var CodeValidator = (function () {
function CodeValidator() {
}
CodeValidator.prototype.isAcceptable = function (s) {
return s.length === 6 && CodeRegexp.test(s);
};
CodeValidator.prototype.toarr = function (s) {
codearr.push(s);
};
return CodeValidator;
}());
Vcode.CodeValidator = CodeValidator;
var strings = ['littDuck', '345633', 'No:177', 'alexzeng'];
var namestring = new Vcode.nameOnlyValidator();
var codestring = new Vcode.CodeValidator();
for (var i in strings) {
if (codestring.isAcceptable(strings[i])) {
codestring.toarr(strings[i]);
}
if (namestring.isAcceptable(strings[i])) {
namestring.toarr(strings[i]);
}
}
console.log(namearr);
console.log(codearr);
})(Vcode || (Vcode = {}));
最后說(shuō)一下籍救,無(wú)論是module X {} 還是 namespace X {}习绢,匯編出來(lái)的js都是一樣的。
以上的例程蝙昙,全部是我自己碼出來(lái)的闪萄,想代碼比寫(xiě)文章困難,轉(zhuǎn)帖的時(shí)候請(qǐng)把涼風(fēng)有興或者AlexZeng.net進(jìn)行署名耸黑。本文版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(創(chuàng)意共享3.0許可證)