TypeScript语言特性(下)

引言:TypeScript是一个开源的、跨平台且带有类型系统的JavaScript超集,它可以编译为纯JavaScript,然后运行在任意的浏览器和其他环境中。
本文选自《Learning TypeScript中文版》一书,在上篇文章中我们了解了TypeScript的类型、变量、基本类型和运算符等语言特性,本文将继续向您介绍流程控制语句、函数、类、接口以及命名空间等语言特性。

流程控制语句

这一节将描述 TypeScript 中的选择语句、循环语句和分支语句。

单一选择结构(if)

下面这段代码声明了一个boolean类型的变量isValid。然后,一个if语句会判断isValid的值是否为true。如果判断结果为true,则在屏幕上会显示消息Is valid!。


var isValid : boolean = true;

if(isValid) {
  alert("is valid!");
}

双选择结构(if…else)

下面这段代码声明了一个boolean类型的变量isValid。然后,一个 if语句会判断isValid的值是否为true。如果判断结果为true,则在屏幕上会显示消息Is valid!。另一方面,如果判断结果为 false,在屏幕上会显示消息Is NOT valid!。

var isValid : boolean = true;

if(isValid) {
  alert("Is valid!");
}
else {
  alert("Is NOT valid!");
}

三元操作符(?)

三元操作符是双选择结构的一种替代形式。

var isValid : boolean = true;
var message = isValid ? "Is valid!" : "Is NOT valid!";
alert(message);

上面这段代码声明了一个boolean类型的变量isValid。然后它判断操作符 ? 左边的变量或表达式是否等于true。
如果判断结果为true,则会执行冒号左边的表达式,Is valid!会被赋值给变量message。
另一方面,如果判断结果为false,则会执行冒号右边的表达式,Is NOT valid!会被赋值给变量message。
最后,变量message的值会显示在屏幕上。

多选结构(switch)

switch语句接受一个表达式,将表达式的值与 case 语句进行匹配,然后执行关联到这种情况下的语句。switch语句经常与枚举类型的变量一起使用来提高代码的可读性。
在下面这个例子中,我们声明了一个接受枚举类型参数AlertLevel的函数。我们在这个函数内部生成一个字符串数组存储E-mail 地址然后执行switch语句。枚举变量中的每一个选项都对应着switch结构内的一个case:

enum AlertLevel{
  info,
  warning,
  error
}

function getAlertSubscribers(level: AlertLevel) {
  var emails = new Array<string>();

  switch (level) {
    case AlertLevel.info:
      emails.push("cst@domain.com");
      break;
    case AlertLevel.warning:
      emails.push("development@domain.com");
      emails.push("sysadmin@domain.com");
      break;
    case AlertLevel.error:
      emails.push("development@domain.com");
      emails.push("sysadmin@domain.com");
      emails.push("management@domain.com");
      break;
    default:
      throw new Error("Invalid argument!");
  }
  return emails;
}
getAlertSubscribers(AlertLevel.info); // ["cst@domain.com"]
getAlertSubscribers(AlertLevel.warning); //
["development@domain.com", "sysadmin@domain.com"]

变量level的值会与switch中所有的case值进行匹配。如果其中一个值与其匹配,那么与这个case关联的语句将会被执行。一旦这个case语句执行完毕,这个变量的值就会与下一个case进行匹配。
当一个case中的语句执行完毕后,下一个满足条件的case语句就会接着执行。如果break关键字出现在case语句中,程序就不会继续匹配接下来的case语句了。
如果没有匹配到任何case语句,程序寻找可选的default语句,如果找到,它将控制程序进入这个语句并且执行其中的代码。
如果没有找到default语句,程序将会继续执行switch表达式后面的语句。按照惯例,default语句放在最后的位置,但这并不是一个强制性的写法。

语句在顶部进行判断的循环(while)

while语句被用来在满足条件的情况下重复一个操作。比如下面这段代码,声明一个数字类型的变量i,当条件(i 小于 5)满足时,将会执行一个操作(i 加 1 然后在浏览器的控制台中打印它的值)。当这个操作完成后,将会再次判断循环的条件。

var i : number = 0;
while (i < 5) {
i += 1;
console.log(i);
}

在while语句中,语句内的操作只在while条件满足时执行。

语句在底部进行判断的循环(do…while)

do…while语句被用来重复一个操作直到条件不再被满足。比如下面这段代码,声明一个数字类型的变量i,在条件(i 小于 5)满足时一直执行一个操作(i 加 1 然后在浏览器的控制台中打印它的值)。

var i: number = 0;
do {
  i += 1;
  console.log(i);
} while (i < 5);

和while语句不一样,do…while语句会在判断while条件是否满足之前至少执行一次,不管条件是否满足。

迭代对象的属性(for…in)

for…in语句本身并不是一个坏的实践,然而它可能会被滥用。例如,迭代一个数组或者类数组对象。for…in语句的原意是枚举对象的属性。

var obj: any = { a: 1, b: 2, c: 3 };
for (var key in obj) {
  console.log(key + " = " + obj[key]);
}

// 输出:
// "a = 1"
// "b = 2"
// "c = 3"

这段代码会沿着原型链,将继承的属性也进行枚举。for…in语句会沿着对象的原型链迭代,枚举出包括继承的属性的所有属性。如果只想枚举对象自己的属性(非继承属性),可以使用hasOwnProperty方法:

for (var key in obj) {
  if (obj.hasOwnProperty(prop)) {
    // prop没有被继承
  }
}

计数器控制循环(for)

for语句会创建一个包含三个可选表达式的循环,表达式在圆括号中用分号分隔,紧跟一个或者一些在循环中执行的语句:

for (var i: number = 0; i < 9; i++) {
  console.log(i);
}

上面这段代码包含一个for语句,它以声明一个变量i并初始化为0开始。第二个语句判断i是否小于9,然后每次循环的时候将i加1。
函数
就像 JavaScript 一样,TypeScript 的函数也可以通过具名或匿名的方式创建。这使我们可以根据应用中的具体情况,选择合适的方式,不论是在构建API时,或创建供其他函数调用的中间函数时。

// 具名函数
function greet(name?: string): string {
  if (name) {
    return "Hi! " + name;
  }
else
{
    return "Hi!";
  }
}

// 匿名函数
var greet = function(name?: string): string {
  if (name) {
    return "Hi! " + name;
  }
else
{
    return "Hi!";
  }
}

正如上述代码所示,在 TypeScript 中,不仅可以为函数的参数加上类型,也可以给函数的返回值指定类型。TypeScript 会通过查看函数里的return语句,来检查返回值的类型正确与否,并且它们都不是必需的。
如果不想使用函数语法,还有另一种语法可以选择,也可以在函数的返回值类型后加上箭头(=>)操作符并不使用function关键字:

var greet = (name: string): string => {
  if (name) {
    return "Hi! " + name;
  }
  else {
    return "Hi! my name is " + this.fullname;
  }
};

使用这种语法声明的函数通常都称作箭头函数。继续回到上述例子,还可以给greet变量添加上匹配匿名函数的类型。

var greet: (name: string) => string = function(name: string):
  string {
  if (name) {
    return "Hi! " + name;
  }
else
{
    return "Hi!";
  }
};

现在我们已经学习了如何将一个变量强制描述为指定形式的函数。这在我们使用回调函数(作为另一个函数的参数)时,十分有用。

function sume(a: number, b: number, callback: (result: number)
  => void) {
  callback(a + b);
}

在上述例子里,我们声明了一个名为sume的函数,并且指定了两个number类型的参数和第三个函数类型的callback参数。回调函数上的类型声明将会限制callback参数为一个仅接受一个number类型的参数,且无返回值的函数。

在ECMAScript 6(即最新版本的JavaScript)中,添加了基于类的面向对象编程语法。由于 TypeScript 是基于 ES6 的,所以开发者如今就已经可以开始使用基于类的面向对象的语法了。TypeScript的编译器会负责将 TypeScript 代码编译为兼容主流浏览器和平台的 JavaScript 代码。
让我们来看一个在TypeScript中定义类的例子:

class Character {
  fullname: string;
  constructor(firstname: string, lastname: string) {
    this.fullname = firstname + " " + lastname;
  }
  greet(name?: string) {
    if (name) {
      return "Hi! " + name + "! my name is " + this.fullname;
    } else {
      return "Hi! my name is " + this.fullname;
    }
  }
}

var spark = new Character("Jacob", "Keyes");
var msg = spark.greet();
alert(msg); // "Hi! my name is Jacob Keyes"
var msg1 = spark.greet("Dr. Halsey");
alert(msg1); // "Hi! Dr. Halsey! my name is Jacob Keyes"

在上面的例子里,我们定义了一个名为Character的新类。这个类有三个成员:一个名为fullname的属性,一个构造函数constructor,和一个greet方法。当我们在 TypeScript 中声明类时,所有的属性和方法默认都是公共的。
你可能已经留意到,当(在对象内部)访问对象内的成员时,我们都在前面加上了this操作符,this操作符表明了这是一个成员访问操作。我们使用new操作符构造了Character类的一个实例,这会调用类的构造函数,按照定义对实例进行初始化。
为了兼容 ECMAScript 3 和 ECMAScript 5,TypeScript中的类会被编译为 JavaScript 中的函数。

接口

在 TypeScript 中,可以使用接口来确保类拥有指定的结构。

interface LoggerInterface {
  log(arg: any): void;
}
class Logger implements LoggerInterface {
  log(arg) {
    if (typeof console.log === "function") {
      console.log(arg);
    } else {
      alert(arg);
    }
  }
}

在上面的例子里,我们定义了一个名为loggerInterface的接口,和一个实现了它的Logger类。TypeScript也允许使用接口来约束对象。这使我们可以避免很多潜在的小错误,尤其是在写对象字面量时:

interface UserInterface{
  name : string;
  password : string;
}
var user : UserInterface = {
  name : "",
  pasword : "" // password遗漏错误属性
};

命名空间

命名空间,又称内部模块,被用于组织一些具有某些内在联系的特性和对象。命名空间能够使代码结构更清晰,可以使用namespace和export关键字,在TypeScript中声明命名空间。

namespace Geometry{
  interface VectorInterface {
  /* ... /
  }
  export interface Vector2dInterface {
    / ... /
  }
  export interface Vector3dInterface {
    /* ... /
  }
  export class Vector2d implements VectorInterface, Vector2dInterface {
    /* ... /
  }
  export class Vector3d implements VectorInterface, Vector3dInterface {
    /* ... /
  }
}

var vector2dInstance: Geometry.Vector2dInterface = new Geometry.Vector2d();
var vector3dInstance: Geometry.Vector3dInterface = new Geometry.Vector3d();

在上面的例子里,我们声明了一个包含了Vector2d、Vector3d类和VectorInterface、Vector2dInterface、Vector3dInterface接口的命名空间。注意,命名空间内的第一个接口声明前并没有export关键字。所以,在命名空间的外部,我们访问不到它。
本篇文章的上半部分请访问TypeScript语言特性(上)。
想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。

时间: 2024-12-24 22:11:22

TypeScript语言特性(下)的相关文章

TypeScript语言特性(上)

引言:TypeScript是一个开源的.跨平台且带有类型系统的JavaScript超集,它可以编译为纯JavaScript,然后运行在任意的浏览器和其他环境中.它使开发者可以使用一些未来JavaScript标准(ECMAScript 6和7)中的特性.TypeScript为JavaScript添加了可选的静态类型.类和模块,让大型JavaScript应用可以使用更好的工具并拥有更清晰的结构. 本文选自<Learning TypeScript中文版>一书,本文将带您了解类型.变量.基本类型和运算

J2SE 5.0专题 之 语言特性

j2se J2SE 5.0专题 之 语言特性                         本文作者: 高宇翔(大胃) 1.1.        背景J2SE(TM) 5.0正式发布至今已超过3个月的时间了,就在前不久,大概是在两周之前,Sun又发布了更新过的JDK 5.0 Update 1,改掉了一些第一个版本中出现的bug. 由于Java社群等待这一从1.4向5.0版本升级已经有相当长的一段时间,大家都很关心5.0中有哪些值得关注的变化,于是blog的相关信息满天飞,我也兴冲冲地在自己的bl

无人使用的Java语言特性

JavaLobby上的一位读者兼作者读了Java十大最无用特性之后,也列出了自己心中无人使用的Java语言 特性,大家也可以过来评评 之前,我在JavaLobby上读了Anthony Goubard的"Java10大最无用的特性".我同意他的一些选择,但我 认为他忽略了一些无人使用的关键特性.我仅将自己限制在语言级特性上(API 太庞大了),下面是另外 4个未被使用的Java特性. 1. 严格的浮点数 也许在某个地方,Java的strictfp关键字对某个程序员十分重要,但我还没遇到过

LINQ体验(3)——C# 3.0新语言特性和改进(下篇)

上一篇我们介绍了C# 3.0新语言特性和改进上部分,这篇我们继续介绍剩下 的部分. C# 3.0新语言特性和改进包括: 自动属性(Auto- Implemented Properties) 隐含类型局部变量(Local Variable Type Inference) 匿名类型(Anonymous Types) 对象与集合初始化器 (Object and Collection Initializers) 扩展方法(Extension Methods) Lambda表达式和Lambda表达式树 (

LINQ体验(2)——C# 3.0新语言特性和改进(上篇)

在第一篇中,知道了Visual Studio 2008新特性,从这篇开始进入此系列的 第二部分--介绍C# 3.0新语言特性和改进. 总体来说, Visual Studio 2008和.NET 3.5是建立在.NET2.0核心的基础之上,.NET2.0核心 本身将不再变化(如果不了解.NET2.0的朋友,请参看MSDN或者一些经典的书籍 ),C# 3.0新语言特性在.NET2.0基础上进行了改进,这些改进的功能可以大大 简化我们编写程序.关于C# 3.0新语言特性在博客园里的很多朋友都介绍了,我

理解Javascript的动态语言特性

  这篇文章主要介绍了理解Javascript的动态语言特性,需要的朋友可以参考下 Javascript是一种解释性语言,而并非编译性,它不能编译成二进制文件. 理解动态执行与闭包的概念 动态执行:javascript提供eval()函数,用于动态解释一段文本,并在当前上下文环境中执行. 首先我们需要理解的是eval()方法它有全局闭包和当前函数的闭包,比如如下代码,大家认为会输出什么呢? ? 1 2 3 4 5 6 7 var i = 100; function myFunc() { var

C++ 语言特性的性能分析

大多数开发人员通常都有这个观点,即汇编语言和 C 语言适合用来编写对性能要求非常高的程序.而 C++ 语言的主要应用范围是编写复杂度非常高的程序,但是对性能要求不是那么严格的程序.但是事实往往并非如此,很多时候,一个程序的速度在框架设计完成时大致已经确定了,而并非是因为采用了C++语言才使其速度没有达到预期的目标.因此当一个程序的性能需要提高时,首先需要做的是用性能检测工具对其运行的时间分布进行一个准确的测量,找出关键路径和真正的瓶颈所在,然后针对瓶颈进行分析和优化,而不是一味盲目地将性能低劣归

C# 动态语言特性,dynamic 关键字研究

原文:C# 动态语言特性,dynamic 关键字研究 1       动态语言简介 支持动态特性的语言现在大行其道,并且有继续增长的趋势.比如 Ruby 和 Python, 还有天王级的巨星 --- JavaScript. 现在一个程序员说自己对 JavaScript 根本没使用过,别人一定把你当成从火星回来的吧! 很多使用过 JavaScript 的程序员,刚开始对其动态特性深恶痛绝,欲除之而后快,但是一旦熟悉这个语言以后,又会发疯般的爱上她(我的野蛮女友). 以创建一个"人"为例,

新Orcas语言特性-查询句法_oracle

[原文地址]New "Orcas" Language Feature: Query Syntax [原文发表日期] Saturday, April 21, 2007 2:12 上个月我开始了一个贴子系列,讨论作为Visual Studio和.NET框架Orcas版本一部分发布的一些新的VB和C#语言特性.下面是该系列的前三篇贴子的链接: 自动属性,对象初始化器,和集合初始化器 扩展方法 Lambda表达式 今天的贴子要讨论另一个基础性的新语言特性:查询句法(Query Syntax).