Typescript中文教程-接口

Typescript 的一个核心原则是类型检查关注于值的‘类型’。有时被称作‘鸭子类型’(duck typing)或‘结构类型’(structural subtyping)。在typescript里,接口扮演了命名这些类型的角色,同时也是在你的代码和链接你的外部工程里定义链接的有力方法。

1、我们的第一个接口interface

查看接口如何工作的最简单的方法是开始一个简单的实例:

1
2
3
4
5
6
function printLabel(labelledObj: {label: string}) {
  console.log(labelledObj.label);
}
var myObj = {size: 10, label: “Size 10 Object”};
printLabel(myObj);

类型检查将检查调用‘printLable’。‘printLable’函数有一个带有原型‘lable’类型为字符串string的对象参数。需要注意的是我们传入的对象实属性际要比此要多,但是最终编辑器只是检查符合参数要求的那个属性。

我们再写一次同样的例子,这一次使用接口来描述此函数需要一个字符串类型的属性‘lable’:

1
2
3
4
5
6
7
8
9
10
interface LabelledValue {
  label: string;
}
function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}
var myObj = {size: 10, label: “Size 10 Object”};
printLabel(myObj);

接口‘LabledValue’是一个可以用来描述我们前面例子函数需求的名称。它同样要求有一个属性叫做‘lable’并且类型是字符串string。需要注意的是我们不需要像其他语言那样明确的声明我们传入‘printLable’实例的对象。这里主要是‘类型’起到关键作用。如果传入函数的对象符合要求就行。

值得指出的是类型检查器不会要求这些属性按照一定的顺序,只要接口的要求的属性出现并且是正确的类型即可。

2、可选属性

不是接口的所有属性都是必须的。一些存在特定的条件或者可能根本不存在。这些可选的属性在选择袋(option bags),即传入一个函数的只有一个对象,在填补了几个属性时,这种方式很受欢迎。

这里以下面的模式为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface SquareConfig {
  color?: string;
  width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
  var newSquare = {color: “white”, area: 100};
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}
var mySquare = createSquare({color: “black”});

可选的接口和其他接口类似,只是在每个可选属性里加入‘?’作为属性的声明的一部分。

可选属性的好处是,可以描述可能使用的属性同时捕捉到不应该被使用的属性。例如,我们传入‘createSquare’函数里的属性名字打错啦,编译器将会通知我们一个错误消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface SquareConfig {
  color?: string;
  width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
  var newSquare = {color: “white”, area: 100};
  if (config.color) {
    newSquare.color = config.collor;  // Type-checker can catch the mistyped name here
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}
var mySquare = createSquare({color: “black”});

 

3、函数类型

接口也能够描述javascript对象包含的更宽范围的‘类型’。在添加一个对象的属性时,接口同样能描述函数的类型。

要用接口描述一个函数的类型,我们给这个接口一个调用签名。这是一个只有参数列表和返回值的函数声明。

1
2
3
interface SearchFunc {
  (source: string, subString: string): boolean;
}

一但我们定义了之后就可以像其他接口一样使用函数类型的接口。这里,我们展示如何通过创建一个函数类型的变量然后设置他的函数值是同样的类型。

1
2
3
4
5
6
7
8
9
10
var mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
  var result = source.search(subString);
  if (result == -1) {
    return false;
  }
  else {
    return true;
  }
}

对于函数类型的正确类型检查来说,参数的名字并不一定要一致。例如我们可以将上面的例子改写成下面这样:

1
2
3
4
5
6
7
8
9
10
var mySearch: SearchFunc;
mySearch = function(src: string, sub: string) {
  var result = source.search(subString);
  if (result == -1) {
    return false;
  }
  else {
    return true;
  }
}

函数的参数检查时每个类型对应参数的位置互相检查。同样我们的函数表达式的返回类型暗示了它返回的值(这里是真或假)。若函数返回的是数字或字符串,类型检查其将通知我们SearchFunc返回值与接口不匹配。

4、数组类型Array Types

跟我们用接口来描述函数类型相似,我们也能描述数组类型。数组类型有一个‘index’类型用来描述允许索引的对象的类型和一个相应的返回类型来访问索引。

1
2
3
4
5
6
interface StringArray {
  [index: number]: string;
}
var myArray: StringArray;
myArray = [“Bob”, “Fred”];

这里有两种索引支持类型,字符串和数字。可以同时支持两种索引形式,但约束数值类型的索引必须是字符类型索引返回类型的子类型。

索引签名是一种非常强有力的描述数组和‘dictionary’模式的方法,同时它也强制所有属性必须符合它的返回类型。在下面这个例子里,属性并没有符合通用索引,类型检查器将返回一个错误:

1
2
3
4
interface Dictionary {
  [index: string]: string;
  length: number;    // error, the type of ‘length’ is not a subtype of the indexer
}

 

5、类类型class types

实现一个接口

在C#或Java等语言里一种最常用的接口是明确地限制一个类符合特定的要求,在typescript里也是可以实现的。

1
2
3
4
5
6
7
8
interface ClockInterface {
    currentTime: Date;
}
class Clock implements ClockInterface  {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

你也可以在一个接口中描述实现类中的方法,我们也用‘setTime’作为例子:

1
2
3
4
5
6
7
8
9
10
11
12
interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}
class Clock implements ClockInterface  {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

接口描述类的公共方面而不是其私有方面。这将阻止你用它来检查一个类实例也有特殊的私有方面的类型。

6、静态/实例的类之间的区别

在处理类和接口时,它有助于记住一个类两种类型:静态的类型和实例的类型。您可能会注意到,如果你通过构造签名创建一个接口并尝试创建一个类实现该接口你会得到一个错误:

1
2
3
4
5
6
7
8
interface ClockInterface {
    new (hour: number, minute: number);
}
class Clock implements ClockInterface  {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

这是因为当一个类使用接口时,只检查实例的类。由于构造函数是静态的将不会被检查。

然而,您将需要直接使用类“静态”的一面。在这个例子我们直接使用类:

1
2
3
4
5
6
7
8
9
10
11
interface ClockStatic {
    new (hour: number, minute: number);
}
class Clock  {
    currentTime: Date;
    constructor(h: number, m: number) { }
}
var cs: ClockStatic = Clock;
var newClock = new cs(7, 30);

 

7、扩展接口

就像类,接口可以互相扩展。这个处理的任务复制一个接口的成员到另一个,在你单独的接口为可重用的组件时有更多的自由。

1
2
3
4
5
6
7
8
9
10
11
interface Shape {
    color: string;
}
interface Square extends Shape {
    sideLength: number;
}
var square = <Square>{};
square.color = “blue”;
square.sideLength = 10;

一个接口可以扩展多个接口,创建一个所有组合的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Shape {
    color: string;
}
interface PenStroke {
    penWidth: number;
}
interface Square extends Shape, PenStroke {
    sideLength: number;
}
var square = <Square>{};
square.color = “blue”;
square.sideLength = 10;
square.penWidth = 5.0;

 

8、混合型

正如我们前面所提到的,接口可以描述出现在现实世界JavaScript的丰富的类型。由于JavaScript的动态和灵活的性质,你偶尔会遇到一个对象,是上面描述的一些类型的组合。

例子是一个对象,作为一个函数和一个对象的附加属性:

1
2
3
4
5
6
7
8
9
10
interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}
var c: Counter;
c(10);
c.reset();
c.interval = 5.0;

与第三方JavaScript交互,您可能需要使用像上面完全描述的形状类型的模式。

Typescript中文教程-基础类型

基础类型(Basic Types)

为了使程序正常工作,我们需要以下基本数据类型:numbers数字,structures结构,strings字符串,boolean布尔型值等等。在typescript中,通过注入一种方便的枚举类型来帮助typescript支持javascript同样的数据类型。

1、Boolean布尔型

Javascript和typeScript(其他语言同理)同样叫做布尔型‘boolean’的值只包含最简单的两个值真和假(true/false)。

1
var isDone: boolean = false;

 

2、Number数字

跟javaScript一样,typescript所有的数都是浮点数类型。这些浮点数获得类型‘number’。

1
var height: number = 6;

 

3、string字符串

另一种在网页和服务器端的基本数据类型是字符型数据。跟其他语言一样,我们用‘string’来表示字符类型的数据。跟javascript一样,typescript也是用单引号‘’或双引号“”来包裹字符串型数据。

1
2
var name: string = “bob”;
name = ‘smith’;

 

4、Array数组

同样typescript也允许使用数组。数组类型可以用两种方法来表示。第一种使用元素的类型和后面紧跟的大括号‘[]’来表示素组每一个元素的类型:

1
var list:number[] = [1, 2, 3];

第二种方法是使用一个通用数组类型,Array<elemType>:

1
var list:Array<number> = [1, 2, 3];

 

5、Enum枚举

一个对javascript很有用的附加标准数据类型是枚举类型’enum’,和C#一样,枚举类型是一种十分友好的给出名称和名称的值的方法。

1
2
enum Color {Red = 1, Green, Blue};
var c: Color = Color.Green;

或者甚至可以手动的设置枚举类型中所有的值。

1
2
enum Color {Red = 1, Green = 2, Blue = 4};
var c: Color = Color.Green;

枚举类型的一种非常方便的特性是根据枚举类型元素的数字的值可以访问到这个元素的名称。例如,我们只知道数值2,但我们并不确定上面枚举类型具体的情况,我们可以查询其相应的名字。

1
2
3
4
enum Color {Red = 1, Green, Blue};
var colorName: string = Color[2];
alert(colorName);

typescript1

6、Any类型

我们可能需要描述我们在写应用时还不确定的变量。这些值可能来自一些动态内容,例如来自第三方库或用户。在这种情况下,我们想要在编译时跳过其类型检查,这时我们需要给它添加‘any’标签。

1
2
3
var notSure: any = 4;
notSure = “maybe a string instead”;
notSure = false; // okay, definitely a boolean

Any类型是一种非常好的方法,帮助我们使用现有的JavaScript,允许你设置在编译时跳入跳出类型检查。

如果你只知道部分类型,‘any’类型也是很好帮助。例如,你有个混合类型元素的数组:

1
2
3
var list:any[] = [1, true, “free”];
list[1] = 100;

 

7、Viod空类型

跟‘any’相反的是‘void’类型,表示完全不含有任何类型的数据。你可能通常在没有返回值的函数中看到它。

1
2
3
function warnUser(): void {
    alert(“This is my warning message”);
}

TypeScript中文教程-新手上路

写在前面

本系列来自 @东北大客 http://14ms.net/ 的翻译,虽然没有全部翻译,但是仍然帮我我这种初学者且英语苦手的大忙。

我在东北大客翻译的基础上改了改错别字和一些描述上的问题,算是一点优化。

原文链接为:http://www.typescriptlang.org/

 

1、安装typescript支持 。

有两种主要方法获得typescript工具:通过node.js的包管理(npm),或者安装VS2012的TypeScript插件。

对于VS 2013用户,点击一下链接:

Install TypeScript for Visual Studio 2013

对于NPM用户:

1
> npm install -g typescript

 

2、在编辑器(如webstrom)中新建greeter.ts文件,敲入一下代码:

 

1
2
3
4
5
6
7
function greeter(person) {
    return “Hello, ” + person;
}
var user = “Jane User”;
document.body.innerHTML = greeter(user);

 

3、编译TypeScript文件

以上文件使用 .ts为扩展名,但实际代码仍为 javascript。可以直接拷贝粘贴至现有的Javascript 程序中。

在命令行里键入 如下命令,运行 TypeScript 编译器

注:当前目录为greeter.ts的目录。

请完成以上步骤1,即已经安装了typeScript支持。

1
> tsc greeter.ts

 

4、类型声明

结果是生成了一个带有相同代码的js文件。TypeScritpt 已经运行起来了。
接下来我们利用TypeScript提供的新工具进行一些改良。给greeter函数的person参数添加“:string”类型声明。

1
2
3
4
5
6
7
function greeter(person: string) {
    return “Hello, ” + person;
}
var user = “Jane User”;
document.body.innerHTML = greeter(user);

 

5、变量控制

类型声明是一种控制函数变量期望的简单方法。在这里,我们期望给greeter函数传递一个字符串类型的产生。我们将传递进来的参数改成数组试一下:

1
2
3
4
5
6
7
function greeter(person: string) {
    return “Hello, ” + person;
}
var user = [0, 1, 2];
document.body.innerHTML = greeter(user);

重新编译将会看到如下的错误:

1
greeter.ts(7,26): Supplied parameters do not match any signature of call target

 

6、接口

同样的,如果将调用greeter函数时不传入任何参数,TypeScript将会告诉你传入的参数个数不符。TypeScript提供根据私有声明和代码结构两种静态分析方法。
需要注意的是,以上仍然会建立greeter.js文件。尽管有错误仍然可以使用TypeScript,但TypeScript将会告知以上代码可能不会按照期望的方式运行。
接下来更进一步的改造我们的例子。我们使用接口interface来描述person对象,其包含名字和姓氏,即firstname和lastname。在TypeScript如果两个类型的内部结构兼容的话就会被兼容。这使得我们可以通过声明接口的形态即可实现接口,而不用详述一个接口的实现条款。

1
2
3
4
5
6
7
8
9
10
11
12
interface Person {
    firstname: string;
    lastname: string;
}
function greeter(person : Person) {
    return “Hello, ” + person.firstname + ” ” + person.lastname;
}
var user = {firstname: “Jane”, lastname: “User”};
document.body.innerHTML = greeter(user);

 

7、类的声明和构造

最后我们扩展类class。TypeScript支持现在的ES6基于类的面向对象程序声明。
下面通过构造函数和几个公有域创建一个Student类,需要注意的是Person和Student可以同时声明,并交给程序正确的抽象出来。

需要注意的是,构造函数的public参数是一种帮助我们快速建立属性的速记方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Student {
    fullname : string;
    constructor(public firstname, public middleinitial, public lastname) {
        this.fullname = firstname + ” ” + middleinitial + ” ” + lastname;
    }
}
interface Person {
    firstname: string;
    lastname: string;
}
function greeter(person : Person) {
    return “Hello, ” + person.firstname + ” ” + person.lastname;
}
var user = new Student(“Jane”, “M.”, “User”);
document.body.innerHTML = greeter(user);

 

8、添加HTML并运行

再运行一次 tsc greeter.js 我们发现生成的js 和以前我们写的代码相同。类class只是帮助我们建立基于OO的原型的方法。
下面添加 greeter.html 并在浏览器里打开就可以看见最终效果了。

1
2
3
4
5
6
7
<!DOCTYPE html>
<html>
    <head><title>TypeScript Greeter</title></head>
    <body>
        <script src=”greeter.js”></script>
    </body>
</html>

前端开发工程师

什么是前端开发工程师

前端开发工程师是Web前端开发工程师的简称,是近五年才真正开始受到重视的一个新兴职业。

这个岗位的职能现在还存在很多争议,尤其是在互联网技术并不发达的地区,但不管如何争执,前端工程师都需要掌握以下几个技能。

  1. HTML
  2. CSS
  3. JavaScript

而争议就在于上面三个技能水平的不同,能做的事情不尽相同,而且其他岗位,如后端开发也要了解这些技能,一些设计也需要会这三个技能,导致了前端工程师的市场出现了一阵的混乱。

而现在,我们将这些可能造成混乱的岗位,根据岗位需要又进行了细分。

 

前端开发工程师的分类

  • 美工:从设计,到页面重构全包的岗位,对上面三个技能的要求都只是熟练而已,互联网行业发达的城市几乎看不到该岗位了;
  • 页面重构师:前两年比较标准的前端工程师,精通HTML、CSS,JavaScript是熟练级别能够很好的使用一些现成的类库和框架就好。
  • 高保真原型开发师:一些公司分工非常细,这个岗位不用写JavaScript,但是Html和Css可能是专家级别的,负责将设计稿高度还原成页面。
  • H5前端开发工程师(JS方向):这个方向的工程师是JavaScript的专家,他们可以不用会写页面,但是写JS是一把好手。
  • H5前端开发工程师:没有特殊说明的H5前端开发工程师,是三项技能都达到精通的开发者,这类开发者用的前端开发技术比较新,倾向于解决移动端开发方案。
  • 移动端前端开发工程师:很多公司以H5开发工程师来招募这个岗位的人员,然而其实H5开发工程师不一定是移动端开发,所以移动端前端开发工程师是专注移动端页面开发的人员,更了解手持设备。
  • 前端架构师:专家级别的js开发工程师,负责造轮子写公司前端UI架构和脚本架构。
  • 还有与设计和动画相关的前端开发岗位在这里就不赘述了…

 

前端工程师需要掌握的知识

上面说了3个基本技能,然而这3个基本技能并非像想象的那么简单,尤其是JavaScript,现在的受欢迎程度节节攀升,重要程度也不再是以前那个只做表单验证的被开发人员们嫌弃的语言。

另外前端作为中游开发,负责接收UI设计进行生产,之后产出给后台同学页面(现在一些开发模式不用给后台同学页面了,因为前端包办了后台模板开发的任务),所以前端作为枢纽,需要庞大的知识面,什么都要了解一些才能得心应手地做前端工作。

那么该掌握什么呢?

  1. 必须熟练掌握基本的web前端技术,比如:css、js、html 等等;
  2. 掌握一个到多个流行的类库(jQuery、zepto等)和框架(Angularjs、backbone、bootstrap等);
  3. 至少掌握或了解一门后端语言(JAVA、PHP、.Net);
  4. 必须掌握网站的性能优化、SEO、UE、服务器端、兼容性、存在的bug等;
  5. 学会用工具辅助开发;
  6. 有良好的代码规范编写习惯。

下面的图形象的说明了前端开发根本就是个百晓生…

35a85edf8db1cb131db54265dd54564e93584be3

做前端很简单,做前端很难

前端这个岗位在开发人员中,无疑是最具趣味性的,这得益于所见即所得的开发本质。

任何有一点代码基础的人,甚至不太懂代码的人都可以很快的写出一个页面,并让它运行在你的浏览器里面。

然而前端开发的学习曲线却是异常地陡峭,因此造成了现在市场上该岗位人才的两极分化,也是现在市场上前端开发供不应求的根本原因。

 

最后说说HTML5

H5前端开发是个奇怪的岗位,因为很多公司招募H5前端开发,其实并不是在用HTML5。

上海这边对稍微高端些的前端开发岗位,尤其是移动端,基本都叫H5开发了。

典型的岗位需求就是你要会一点Nodejs;

要会一个或多个MVVM或MVC框架;

最好会一点Hybrid开发;

能处理手持设备的兼容问题。

 

结语

 

智能手机大爆炸时代,移动端用户大暴涨时代,所有的开发应用势必会秉承移动优先的原则,作为专注移动端开发的HTML5,无疑将是未来开发领域的佼佼者。

几年内,HMTL5已经横跨所有智能平台,让我们拭目以待前端开发工程师多彩的未来。

 

关于js乱码问题

碰到以gbk做基础编码的项目,就可能避免不了编码混乱导致乱码的问题(水平问题和团队问题的产物)。

这里只说js的解决方案。

 

在script标签里面有charset这个参数,我们将该参数设置为你js文件的编码模式就可以解决文件中的乱码问题。

现在市面上的主流IDE都支持在下面状态栏显示编码模式的功能,没看到的话看下帮助。

比如你的文件是一个utf-8编码的文件,我们只要
<script src="xxx.js" charset="utf-8"></script>
就可以,不管你的页面是什么编码,都以将该js文件以utf-8的方式读取并执行。

 

NG的指令绑定策略

本文章所提到的书为《AngularJs权威教程》 Ari Lerner著

 

绑定策略涉及到4个方式,分别为:“@”,=”,“&”

书中对于绑定策略的描述:

 

本地作用域属性:使用@符号将本地作用域同DOM属性的值进行绑定。指令内部作用域可以使用外部作用域变量。

@(or @attr)

 

双向绑定:通过=可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定。就想普通的数据绑定一样,本地属性会反映出父数据模型中所发生的改变。

=(or =attr)

 

父级作用域绑定:通过&符号可以对父级作用域进行绑定,以便在其中运行函数。意味着对这个值进行设置时会生成一个指向父级作用域的包装函数。

要使调用带有一个参数的父方法,我们需要传递一个对象,这个对象的键是参数的名称,值是要传递给参数的内容。

&(or &attr)

 

因为书里面的描述比较简单,这里做一些补充说明:

从传递的内容来说

@ 传递过来的是一个字符串

= 传递过来的是一个字符串或对象

& 这里一定不要认为&传递的是一个函数,实际上父级作用域绑定传递的是一个函数的描述,通过该描述和父级作用域的函数建立联系然后执行。

 

简单的例子,一个有参函数的定义(无参函数比较容易理解这里就不做说明了):
//指令HTML部分
<plug-in callback="fun(value)"><plug-in>
<script type="text/javascript">
//对绑定的方法进行设计
app.run(['$rootScope',function($rootScope){
$rootScope.fun = function(value){
console.log(value);
}
}]);
//指令的设计
app.directive('plugIn',[function(){
return{
replace:true,
scope:{callback:"&"},
template:'<div class="demo"></div>',
restrict: "EA",
link:function($scope){
//执行绑定的方法
$scope.callback({value:1,data:2});
}
}
}])
</script>

IOS不支持浏览器自动播放音乐

说到这个东西,肯定是碰到了这个需求。

直接上文档:
苹果官方文档地址
文档里面有一段注意:

To prevent unsolicited downloads over cellular networks at the user’s expense, embedded media cannot be played automatically in Safari on iOS—the user always initiates playback. A controller is automatically supplied on iPhone or iPod touch once playback in initiated, but for iPad you must either set the controls attribute or provide a controller using JavaScript.

大意就是为了避免不可预期的网络流量,而造成手机用户额外的下载费用,嵌入式的媒体没有办法在ios中自动播放,你需要加个控制器或者按钮(竟然没有机翻我也看得懂了)。

但是需求为大,还是要尽量解决这个问题,难道要我用js写音乐么~
如果这个问题可以得到解决欢迎大家提示我=。=

移动端的select解决方案

lucky-select

https://github.com/gaofeiyu/lucky-select.git

移动端的select解决方案,可级联(现在只有二级联动)。 组件参考自新浪的微招聘,致敬!

基本指令说明

单级指令 singleSelectorPopup 二级联动指令 doubleSelectorPopup 上面两个指令主要是生成下拉部分

参数

//初始化的值
title 标题
initData 初始化的值
data 下拉数据
getRightListData 二级联动通过该属性的方法过滤生成二级菜单,单级联动不存在该属性

这里的data为数组,包含两个必要键值

{id:1,name:"id对应的展示名称"}

方法

  • show(val) val为初始化的对象
  • hide() 隐藏
  • onConfirm() 确认
  • onCancel() 取消

selector单级指令

该指令是在singleSelectorPopup基础上封装的选择的部分,供使用者参考。

        scope: {value: "=", options: "=", name: "@", readonly:"@", index:"="},
        template: "<span class='selector' ng-click='showPopup();'>{{str}}</span>",
        restrict: "EA",

参数说明

  • value 显示在前台的值
  • options 下拉的数据
  • name 下拉标题
  • readonly 是否只读(不弹出下拉,只展示值)
  • index 当前选择值的索引

效果

例图1 例图2

overlay遮罩指令

通用的遮罩指令,也可以用在其他组件上。

指令说明

replace: true,
template: '<div id="overlay"  ng-click="bindClick();"></div>',
restrict:"EA"

方法

  • show(hideCallback) hideCallback会在hide里面回调
  • hide()
  • clear()