Flow之一个新的Javascript静态类型检查器

 更新时间:2015年12月24日 10:01  点击:2018

今天我们兴奋的发布了 Flow 的尝鲜版,一个新的Javascript静态类型检查器。Flow为Javascript添加了静态类型检查,以提高开发效率和代码质量。更明确的说,静态类型检查提供的好处像早期错误检查,帮助你发现一些只有在运行时才能发现的错误,以及代码智能感知,它会帮助代码维护,查找,重构和优化。

我们设计Flow的所有功能构建在现有Javascript规范之上。因为Flow主动地在后台工作,所以额外的编译开销很小。Flow并不要求开发者如何编写代码 —— 她用一套复杂的算法分析你熟悉的代码风格。

Flow仍然在初期阶段,但是我们已经在Facebook使用了。我们希望你在自己的项目中愉快的使用,期待你的反馈。可以访问 flowtype.org 快速开始。

总览

Facebook超爱Javascript;它快,表达性好,而且到处运行,是构建产品的极佳语言。同时,因为没有静态类型让开发者困扰。Bug难以发现(比如,崩溃的原因隐藏很深),代码维护犹如噩梦(比如,在不知道所有依赖的情况下进行重构风险很大)。Flow改进了速度和效率促进了开发者在使用Javascript的生成效率。

在Javascript之上添加一层静态系统并不简单。Javascript的积木(building block)表现力极高,一个简单的类型系统并不能精确组合出应有的语义。为了支持不同的Javascript编程范式和习惯,Flow引入了类似数据流(data-flow)和控制流(control-flow)这类通常用于编译时提取语义的分析技术。然后用提取的信息,加上先进的类型原理来做类型推断。当然,仅有一个强力的静态类型分析还不够 —— Javascript代码库会很大,这要求类型检查必须闪电般快速,才能不打断开发者编辑-运行的流程。Flow按模块执行分析,所有的类型都限制在模块边界以内。这最终形成一个高度并行、增量式的检查架构,类似 Hack 。这使得类型检查响应快速,即使是百万行级别代码。

Flow的类型检查是选择性的 —— 你不需要一次性执行检查所有。然而,Flow背后的设计基于假定大多数Javascript的代码类型是隐式静态类型;虽然类型可能不会到处在代码中出现,它们是以一种可以按照代码正确性推理出来的形式存在于开发者的思路中。一旦可能,Flow就去推断这些类型,意味着它可以不需要改动代码就能发现类型错误。另一发面,一些如存在于框架中的Javascript代码,大量使用了反射使得静态类型推断非常困难。对于这种天然动态的代码,类型检查就会错漏百出,因此Flow提供对此类代码添加信任并继续。这种设计在Facebook内部被大量的Javascript代码库所验证:大多数代码没有通过隐式静态类型检查条目,这些条目让开发者可以不用添加注释就能检查代码类型错误。

这使得Flow从根本上区别于其他Javascript的类型系统(如TypeScript),通过弱化的假设大多数JavaScript代码是动态输入的,并由开发者自己表达哪些代码应该是静态类型。通常来看,这类设计会导致检查覆盖率降低:更少的类型错误被检测到,工具不够高效。然而对于某些情况下是合理的,一般这种设计如果没有通过大量额外的努力就无法对实际开发提供足够多的帮助。尽管如此,Flow让你可以简单就获得这种弱化的类型检查,对于现有代码非常有用。

为了解释这种区别,请看下面的例子:

function onlyWorksOnNumbers(x) {
 return x * 10;
}
onlyWorksOnNumbers(‘Hello, world!');

Flow能够发现这个错误(尝试把数字和字符串相乘),然而另一种更加保守的分析需要显式的标注 x 的类型。在这个玩具般的例子里面并不觉得费力,但是在巨型代码库里面几乎无人去做。Flow可以不用添加注释就能发现这个错误 —— 当然前提是开发者想这样做。

类型系统

Flow的类型系统实现了许多期望中的功能。支持标准基本类型( number ,  string , boolean ),类型之间的隐式转换在除一些特殊情形外是被禁止的。结构类型,如函数、对象和数组也被支持。类型可以是多态的。

也许你会感到意外,Flow没有把 null 和 undefined 当成是上述类型中的任何一种。这两种类型会有多种可能,使用这些类型必须在合理检查的保护之上。其它组合类型(如 string | number )也被支持,这种用法同样需要确保安全。Flow知道缩小类型范围时做动态检查的影响。

让我们用一个例子来描述处理 null 值。下面的程序总是在运行时崩溃,但是一般的类型系统会认为它没有问题:

function length(x) {
return x.length;
}
var total = length('Hello') + length(null);

Flow会在编译时期发现这个错误,并指出 x 可以是null( length 属性不应该被访问)。另外,Flow了解这个程序的控制流,所以简单修改就能让这个程序类型正确:

function length(x) {
 if (x !== null) {
 return x.length;
 } else {
 return 0;
 }
}
var total = length('Hello') + length(null);

Flow还了解JavaScript复杂的对象模型:构造器,方法,原型和它们动态扩展以及绑定。已经试验性去支持类型的复杂操作如:绑定对象,抽取keys等等。我们希望未来这些功能使得让为框架指定具体类型成为可能。

类型错误通常报告为定义和实际值不兼容:比如函数调用的参数不足,对象中不包含要访问的属性,或者把字符串当成数字使用。

最后,Flow支持动态类型( any ),这种类型可以绕过类型系统检查:比如可用 any 表示静态分析无法准确判断而报错的location(通常使用反射的情况)。另外Flow在弱模式下遇到上述类型且没有注释类型的话,会自动假定为 any 。

扩展性

为了拓展,Flow根据模块和其它模块的依赖关系以及其它模块提供的类型接口,单独对每个模块进行检查。要生成类型接口,Flow可能需要在模块边界上进行注释。

Flow在一个后台运行的持久化服务器上,维护着整个代码库的语义信息,一开始Flow会对整个代码做一次分析,然后当一系列文件改动的时候(可能是单个文件改动或者在切换分支的时候),服务器会增量式更新改动文件以及由于类型关联的其它相关文件的语义信息。这样,当开发者试图获取类型错误时,它们已经在服务器上了,相应几乎是立即的。这种服务器架构与 Hack 构建在同一种技术之上。

兼容性

Flow致力于支持最新的JavaScript标准。目前已经支持各种ES6特性如destructuring, classes, extended objects, optional function parameters,以及核心API扩展(比如Map, Set, Promise, 和 new methods on Object, Array, 和 Math)。其它特性(尤其是模块)正在开发中。Flow支持CommonJS / Node.js 规范的模块。

var Hello = React.createClass ({
 render: function() {
 return <div>Hello {this.props.name}</div>;
 }
});

如果你在JSX上使用的class名字有错误,Flow会发现这个问题:

React.render(, ...);

而且,如果你在React class里面使用了React.PropTypes规范,你可以对JSX上的attributes做静态类型检查:

var Hello = React.createClass ({
 propTypes: {
 name: React.PropTypes.string.isRequired
 }
 ...
});

Flow就会发现 <Hello/> 缺少属性的错误,或者 <Hello name={42}/> 属性类型的错误。

更多的关于支持React的细节可以在 文档 中找到。

开源

Flow代码大部分用OCaml实现。代码库在活跃更新并且会在未来几个月快速进化。除了在Facebook范围内的数据代码库中运行外,我们希望Flow的分析引擎能用于构建类似的,无论是JavaScript或者其他的语言工具。请让我们知道你是否想加入!

好了,关于Flow之一个新的Javascript静态类型检查器的全部内容先给大家介绍到这里,后续还会持续更新,敬请关注!

[!--infotagslink--]

相关文章

  • 使用PHP+JavaScript将HTML页面转换为图片的实例分享

    这篇文章主要介绍了使用PHP+JavaScript将HTML元素转换为图片的实例分享,文后结果的截图只能体现出替换的字体,也不能说将静态页面转为图片可以加快加载,只是这种做法比较interesting XD需要的朋友可以参考下...2016-04-19
  • 关于JavaScript中name的意义冲突示例介绍

    在昨天的《Javascript权威指南》学习笔记之十:ECMAScript 5 增强的对象模型一文中,对于一段代码的调试出现了一个奇怪现象,现将源代码贴在下面: 复制代码 代码如下: <script type="text/javascript"> function Person(){}...2014-05-31
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • javascript自定义的addClass()方法

    复制代码 代码如下: //element:需要添加新样式的元素,value:新的样式 function addClass(element, value ){ if (!element.className){ element.className = value; }else { newClassName = element.className; newClas...2014-05-31
  • JavaScript中的this关键字使用方法总结

    在javascritp中,不一定只有对象方法的上下文中才有this, 全局函数调用和其他的几种不同的上下文中也有this指代。 它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下...2015-03-15
  • javascript的事件触发器介绍的实现

    事件触发器从字面意思上可以很好的理解,就是用来触发事件的,但是有些没有用过的朋友可能就会迷惑了,事件不是通常都由用户在页面上的实际操作来触发的吗?这个观点不完全正确,因为有些事件必须由程序来实现,如自定义事件,jQue...2014-06-07
  • 详解javascript数组去重问题

    首先,我想到的是另建一个结果数组,用来存储原始数组中不重复的数据。遍历原始数组依次跟结果数组中的元素进行比较,检测是否重复。于是乎,我写出了如下代码A: Array.prototype.clearRepetitionA = function(){ var resul...2015-11-08
  • JavaScript中逗号运算符介绍及使用示例

    有一道js面试题,题目是这样的:下列代码的执行结果是什么,为什么? 复制代码 代码如下: var i, j, k; for (i=0, j=0; i<10, j<6; i++, j++) { k = i+j; } document.write(k); 答案是显示10,这道题主要考察JavaScript的逗...2015-03-15
  • JavaScript预解析,对象详解

    这篇文章主要介绍了JavaScript预解析,对象的的相关资料,小编觉得这篇文章写的还不错,需要的朋友可以参考下,希望能够给你带来帮助...2021-11-10
  • JavaScript学习笔记整理_setTimeout的应用

    下面小编就为大家带来一篇JavaScript学习笔记整理_setTimeout的应用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-03
  • Javascript类型转换的规则实例解析

    这篇文章主要介绍了Javascript类型转换的规则实例解析,涉及到javascript类型转换相关知识,对本文感兴趣的朋友一起学习吧...2016-02-27
  • 详解JavaScript操作HTML DOM的基本方式

    通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素。 HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。 HTML DOM 模型被构造为对象的树: 通过可编程的对象模型,Java...2015-10-23
  • ActiveX控件与Javascript之间的交互示例

    1、ActiveX向Javascript传参 复制代码 代码如下: <script language="javascript" for="objectname" event="fun1(arg)"> fun2(arg); </script> objectname为ActiveX控件名,通过<object>标签里的id属性设定,如下; 复制...2014-06-07
  • JavaScript获取浏览器信息的方法

    Window有navigator对象让我们得知浏览器的全部信息.我们可以利用一系列的API函数得知浏览器的信息.JavaScript代码如下:function message(){ txt = "<p>浏览器代码名: " + navigator.appCodeName + "</p>";txt+= "<p>...2015-11-24
  • 学习JavaScript设计模式之装饰者模式

    这篇文章主要为大家介绍了JavaScript设计模式中的装饰者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍

    下面小编就为大家带来一篇JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-05-20
  • javascript设计模式之解释器模式详解

    神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
  • 跟我学习javascript的最新标准ES6

    虽然ES6都还没真正发布,但已经有用ES6重写的程序了,各种关于ES789的提议已经开始了,这你敢信。潮流不是我等大众所能追赶的。潮流虽然太快,但我们不停下学习的步伐,就不会被潮流丢下的,下面来领略下ES6中新特性,一堵新生代JS...2015-11-24
  • JavaScript操作URL的相关内容集锦

    ---恢复内容开始---1.location.href.....(1)self.loction.href="http://www.cnblogs.com/url" window.location.href="http://www.cnblogs.com/url" 以上两个用法相同均为在当前页面打开URL页面 (2)this.locati...2015-10-30
  • 基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式

    前言在面向对象的编程范式中,封装都是必不可少的一个概念,而在诸如 Java,C++等传统的面向对象的语言中, 私有成员是实现封装的一个重要途径。但在 JavaScript 中,确没有在语法特性上对私有成员提供支持, 这也使得开发人员使...2015-10-30