typescript动态属性-TypeScript 和 JavaScript 之间的区别

在 TypeScript 中编写涉及 DOM 对象的 JavaScript 代码通常不会遇到问题。 但这并不是由于 TypeScript 语言对 DOM 对象的“理解”,而是因为 TypeScript 会默认加载一个名为 lib.d.ts 的声明文件,该文件默认包含所有 DOM 对象的声明。 换句话说,当你写下这句话时:

当时编译器其实已经在开头隐式添加了一句话:

这种声明称为环境声明(ambient declaration)。 遇到环境声明后,TypeScript 会尝试从声明的来源(例如声明库)分析并推断对象的类型信息。 如果没有找到源,则默认对象的类型为any。 但无论如何,环境声明不会向生成的 JavaScript 添加任何句子。 事实上,所有 TypeScript 声明都不会生成相应的 JavaScript 语句,因为 JavaScript 对象模型中的声明是可选的。 从这里也可以看出,TypeScript 秉承“除非必要,否则不要生成冗余单词”的理念。 但断言不仅在 TypeScript 中起到了提前提供类型信息的重要作用,而且编译器可以根据这些信息完成强大的类型推断和准确的静态类型检测。

数据语义

TypeScript 中的数据需要有明确的类型。 如果它被设置为一个类型,但是给它赋值了该类型中的非法值,静态类型检测机制会将这样的句子标记为错误。

您可以使用interface关键字来定义命名结构类型,这类似于在JavaScript中使用文字来定义JavaScript对象。 不同的是,在 TypeScript 中,每个组件都必须指定类型,但组件可以是可选的,并且在实际提供文字对象时可能不会提供可选组件。

同样,接口的数据类型定义以及在 TypeScript 中为数据指定的任何静态类型声明在任何生成的 JavaScript 对象代码中都将不可见。 例如前面的代码生成的JavaScript对象代码只有:

函数对象的类型主要由其签名决定,包括每个方法参数的名称、类型和返回值类型。

值得注意的是,函数对象的返回值可以是void,这是void类型唯一可以出现的地方,而且它唯一可能的值为undefined。

函数语义

TypeScript 中的函数不仅在 JavaScript 函数对象模型的基础上增加了静态类型检测,体现了函数的数据方面,还减少了函数本身本质上的很多新特性,比如函数的默认参数值:

它会相应生成如下JavaScript目标代码,从中可以清楚地看出,其代码生成的逻辑是通过判断参数是否定义来进行的:

TypeScript 支持有限的函数重载,为什么会受到限制呢? 因为通常意义上的函数重载是基于函数签名的差异,所以当函数实际被调用时,会根据实际参数的类型绑定到特定的重载函数。 其背后的实现机制主要是所谓的名称修改。 但 TypeScript 中的函数重载无法做到这一点。 它仅支持基于共享实现主体的重载。 无论声明多少个具有相同名称和不同签名的函数,它都只能有一个实现体,并且这个实现体必须对所有重载版本都有意义。 这么说可能会让人感到困惑,我们来看一个例子:

只要看看上面 TypeScript 代码生成的 JavaScript 目标代码,你就会明白大部分内容:

原因是 TypeScript 在实现重载时并没有使用 name mangling 机制,而 JavaScript 也不支持重载,所以我们只能做出这么特别大的妥协。

TypeScript 中函数对象最引人注目的功能之一是支持所谓的“箭头表示法”或 Lamda 表达式。 例如,以下三个函数是等效的:

但箭头表示法最重要的用途是当需要回调函数时。 此时最容易犯的错误之一是 this 的作用域不再保留在被调用函数的本地作用域中,而是成为函数调用者的作用域。 或者通过一个例子:

此时点击页面,弹出的警告框中显示的值为“NAN”,显然有问题。 这里的问题是,this指的是函数调用者的作用域,这里变成了全局作用域,结果自然是错误的。 这时候只要改用箭头表示法,问题就解决了:

这个表示法是 ECMAScript 6 引入的typescript动态属性,看一下 TypeScript 生成的目标代码就可以明白,它采用了一种迂回的方式来达到疗效,同时保持向上兼容性。

类和继承语义

TypeScript 对 JavaScript 对象模型最重要的扩展自然是它补充了 JavaScript 中尚未引入的“类”概念。 是的,JavaScript 中没有类,只有对象。 要实现所谓的“经典操作”,比如封装、多态等,必须通过几个基础设施来完成,比如原型和构造函数。 这些任务对于非常熟悉 JavaScript 的程序员来说可能可以完成,但对于新手来说却很难。 而且,即使是资深人士,如果一段时间不写相关代码,也很容易忘记、犯错误。 然而,TypeScript 提供了一种标准机制,将普通程序员熟悉的、C++、C# 中常用的类概念映射到 JavaScript,这大大降低了 JavaScript 中执行类操作的难度。 由于相关概念并不难理解,但是技术含量较多,所以这里只介绍几个关键的。

首先用一句话概括TypeScript中类的核心语义:所有的类都是立即函数,所有的数据成员都是这个函数实例的属性,所有的方法都是这个函数原型的属性,所有的静态成员都是构造函数的属性这个功能。 一切就位,你不会出错。 只需查看该类生成的 JavaScript 对象代码即可。 假设有一个 Human 类,根据教学年限估算薪资,定义如下:

它生成的JavaScript对象代码如下:

值得注意的是,TypeScript 支持所谓的“访问器”。 使用访问器,可以将函数封装并公开为数据属性。 例如,您可以添加一个访问器来获取上述类的工资金额:

对应的JavaScript代码比较复杂,浏览器需要支持ECMAScript 5才能运行:

代码组织与构建

TypeScript 中引入了模块的概念,类似于 C++ 中的名称子空间。 它可以将声明、数据、函数和类封装在模块中,并使用export关键字将它们导入以供模块外部的代码访问。 之所以类似于命名空间,是因为可以手动合并同名的模块,甚至可以单独存储在多个文件中; 二是模块的名称可以分为不同的级别,级别多时可以简化名称。 的另一个名字。 但无论模块如何组织,最终结果都是标准的、随时可用的 JavaScript 代码。 正是由于其模块化和可插拔的结构,TypeScript 可以在保持较小的语言核心的同时,为 jQuery、CommonJS 和 Node.js 等广泛使用的库提供完整的支持。

由于 TypeScript 不使用粗略的字符串匹配形式来推断变量和函数名称,因此 TypeScript 代码的命名结构与 Google 的其他编程语言一样简单。 您只需选择要重命名的实体,并输入新名称,而不必担心其他同名但不同含义的实体也会同时被重命名。

概括

TypeScript 是唯一完全兼容的解决方案,并且作为当今 JavaScript 所有改进的超集而存在。 此外,TypeScript 改进了 JavaScript 对象模型的几乎所有方面。 本文仅介绍了一些比较重要的技术,还有很多细节需要读者自行探索。 现在,TypeScript 的最新版本是 0.8.1,并且完整的源代码已经开放。 非常有趣的是,TypeScript 本身就是用 TypeScript 实现的。 这种递归结构也是编译器专家首选的形式之一typescript动态属性,因为 Bjarne Stroustrup 也使用 C++ 本身编写了 C++ 编译器。 熟悉TypeScript源码和规范不仅能让我们更快地掌握这门新语言,还能更深入地了解如何使用它来解决一些更复杂的问题,比如如何扩展它来支持只有TypeScript提供的JavaScript一些特定的浏览器功能等等。总而言之,TypeScript 可以说是最有希望扩展甚至取代 JavaScript 的解决方案之一。 对后端技术感兴趣的同学应该尽快熟悉一下。