认识 Flow

Flow 是 facebook 出品的 JavaScript 静态类型检查⼯具。Vue.js 的源码利⽤了 Flow 做了静态类型检查, 所以了解 Flow 有助于我们阅读源码

Flow 的官方文档

为什么⽤ Flow

JavaScript 是动态类型语⾔,它的灵活性有⽬共睹,但是过于灵活的副作⽤是很容易就写出⾮常隐蔽的 隐患代码,在编译期甚⾄看上去都不会报错,但在运⾏阶段就可能出现各种奇怪的 bug。

类型检查是当前动态类型语⾔的发展趋势,所谓类型检查,就是在编译期尽早发现(由类型错误引起 的)bug,⼜不影响代码运⾏(不需要运⾏时动态检查类型),使编写 JavaScript 具有和编写 Java 等强 类型语⾔相近的体验。

项⽬越复杂就越需要通过⼯具的⼿段来保证项⽬的维护性和增强代码的可读性。 Vue.js 在做 2.0 重构的 时候,在 ES2015 的基础上,除了 ESLint 保证代码⻛格之外,也引⼊了 Flow 做静态类型检查。

之所以 选择 Flow,主要是因为 Babel 和 ESLint 都有对应的 Flow 插件以⽀持语法,可以完全沿⽤现有的构建 配置,⾮常⼩成本的改动就可以拥有静态类型检查的能⼒。

Flow 的⼯作⽅式

通常类型检查分成 2 种⽅式:

类型推断:通过变量的使⽤上下⽂来推断出变量类型,然后根据这些推断来检查类型。它不需要任何代码修改即可进⾏类型检查,最⼩化开发者的⼯作量。它不会强制你改变开发习惯,因 为它会⾃动推断出变量的类型。

这就是所谓的类型推断,Flow 最重要的特性之⼀。 通过⼀个简单例⼦说明⼀下

/*@flow*/``
function split(str) {
return str.split(' ')
}
split(11) // 会报错:str.split is not a function // Flow 检查上述代码后会报错,因为函数 split 期待的参数是字符串,⽽我们输⼊了数字

类型注释:事先注释好我们期待的类型,Flow 会基于这些注释来判断。

如上所述,类型推断是 Flow 最有⽤的特性之⼀,不需要编写类型注释就能获取有⽤的反馈。但在某些 特定的场景下,添加类型注释可以提供更好更明确的检查依据。

/*@flow*/
function add(x, y){
return x + y
}
add('Hello', 11)

Flow 检查上述代码时检查不出任何错误,因为从语法层⾯考虑, + 即可以⽤在字符串上,也可以⽤ 在数字上,我们并没有明确指出 add() 的参数必须为数字。 在这种情况下,我们可以借助类型注释来指明期望的类型。

类型注释是以冒号 : 开头,可以在函数 参数,返回值,变量声明中使⽤。 如果我们在上段代码中添加类型注释,就会变成如下

/*@flow*/

function add(x:number, y:number): number{
return x + y
}
add(11, 11)

现在 Flow 就能检查出错误,因为函数参数的期待类型为数字,而我们提供了字符串。

上面的例子是针对函数的类型注释。接下来我们来看看 Flow 能支持的一些常见的类型注释。

数组:数组类型注释的格式是 Array<T>T 表示数组中每项的数据类型。在上述代码中,arr 是每项均为数字的数组。如果我们给这个数组添加了一个字符串,Flow 能检查出错误

/*@flow*/

var arr: Array<number> = [1, 2, 3]
arr.push('Hello')

类和对象:类的类型注释格式如上,可以对类自身的属性做类型检查,也可以对构造函数的参数做类型检查。这里需要注意的是,属性 y 的类型中间用 | 做间隔,表示 y 的类型即可以是字符串也可以是数字。

对象的注释类型类似于类,需要指定对象属性的类型。

/*@flow*/

class Bar {
x: string; // x 是字符串
y: string | number; // y 可以是字符串或者数字
z: boolean; constructor(x: string, y: string | number) {
this.x = x
this.y = y
this.z = false
}
} var bar: Bar = new Bar('hello', 4) var obj: { a: string, b: number, c: Array<string>, d: Bar } = {
a: 'hello',
b: 11,
c: ['hello', 'world'],
d: new Bar('hello', 3)
}

Null:若想任意类型 T 可以为 null 或者 undefined,只需类似如下写成 ?T 的格式即可

/*@flow*/

var foo: ?string = null // 此时,foo 可以为字符串,也可以为 null

Flow 在 Vue.js 源码中的应用

有时候我们想引用第三方库,或者自定义一些类型,但 Flow 并不认识,因此检查的时候会报错。为了解决这类问题,Flow 提出了一个 libdef 的概念,可以用来识别这些第三方库或者是自定义类型,而 Vue.js 也利用了这一特性。

在 Vue.js 的主目录下有 .flowconfig 文件, 它是 Flow 的配置文件

这其中的 [libs] 部分用来描述包含指定库定义的目录,默认是名为 flow-typed 的目录。

这里 [libs] 配置的是 flow,表示指定的库定义都在 flow 文件夹内。我们打开这个目录,会发现文件如下

flow
├── compiler.js # 编译相关
├── component.js # 组件数据结构
├── global-api.js # Global API 结构
├── modules.js # 第三方库定义
├── options.js # 选项相关
├── ssr.js # 服务端渲染相关
├── vnode.js # 虚拟 node 相关
												

vue源码分析—认识 Flow的更多相关文章

  1. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  2. vue 快速入门 系列 —— 侦测数据的变化 - [vue 源码分析]

    其他章节请看: vue 快速入门 系列 侦测数据的变化 - [vue 源码分析] 本文将 vue 中与数据侦测相关的源码摘了出来,配合上文(侦测数据的变化 - [基本实现]) 一起来分析一下 vue ...

  3. 前端Vue 源码分析-逻辑层

    Vue 源码分析-逻辑层 预期的效果: 监听input的输入,input在输入的时候,会触发 watch与computed函数,并且会更新原始的input的数值.所以直接跟input相关的处理就有3处 ...

  4. [Vue源码分析] v-model实现原理

    最近小组有个关于vue源码分析的分享会,提前准备一下… 前言:我们都知道使用v-model可以实现数据的双向绑定,及实现数据的变化驱动dom的更新,dom的更新影响数据的变化.那么v-model是怎么 ...

  5. Vue源码分析(一) : new Vue() 做了什么

    Vue源码分析(一) : new Vue() 做了什么 author: @TiffanysBear 在了解new Vue做了什么之前,我们先对Vue源码做一些基础的了解,如果你已经对基础的源码目录设计 ...

  6. vue源码分析—Vue.js 源码目录设计

    Vue.js 的源码都在 src 目录下,其目录结构如下 src ├── compiler # 编译相关 ├── core # 核心代码 ├── platforms # 不同平台的支持 ├── ser ...

  7. Vue 源码分析—— 目录结构

    一,Vue.js 的源码都是在src 目录下,其目录结构如下. 1.compiler 目录包含Vue.js 所有编译相关的代码.它包括把所有模板解析成ast 语法树, ast 语法树优化等功能. 2. ...

  8. vue源码分析—Vue.js 源码构建

    Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下.(Rollup 中文网和英文网) 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.j ...

  9. vue源码分析之new Vue过程

    实例化构造函数 从这里可以看出new Vue实际上是使vue构造函数实例化,然后调用_init方法 _init方法,该方法在 src/core/instance/init.js 中定义 Vue.pro ...

随机推荐

  1. Netty1:初识Netty

    为什么使用Netty Netty是业界最流行的NIO框架之一,它的健壮性.功能.性能.可定制性.可扩展性在同类框架中都是首屈一指的,它已经得到了成百上千的商用项目的证明.对于为什么使用Netty这个话 ...

  2. 缓存穿透,缓存雪崩,热点key及解决办法

    1.穿透 穿透:频繁查询一个不存在的数据,由于缓存不命中,每次都要查询持久层.从而失去缓存的意义. 解决办法: 持久层查询不到就缓存空结果,查询时先判断缓存中是否exists(key) ,如果有直接返 ...

  3. [Inside HotSpot] C1编译器优化:条件表达式消除

    1. 条件传送指令 日常编程中有很多根据某个条件对变量赋不同值这样的模式,比如: int cmov(int num) { int result = 10; if(num<10){ result ...

  4. 理解ASP.NET Core验证模型(Claim, ClaimsIdentity, ClaimsPrincipal)不得不读的英文博文

    这篇英文博文是 Andrew Lock 写的 Introduction to Authentication with ASP.NET Core . 以下是简单的阅读笔记: -------------- ...

  5. ASP.NET Core MVC应用程序中的后台工作任务

    在应用程序的内存中缓存常见数据(如查找)可以显着提高您的MVC Web应用程序性能和响应时间.当然,这些数据必须定期刷新. 当然你可以使用任何方法来更新数据,例如Redis中就提供了设定缓存对象的生命 ...

  6. .NET Core微服务之基于MassTransit实现数据最终一致性(Part 1)

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.预备知识:数据一致性 关于数据一致性的文章,园子里已经有很多了,如果你还不了解,那么可以通过以下的几篇文章去快速地了解了解,有个感性认 ...

  7. .NET Core微服务之基于Steeltoe使用Zipkin实现分布式追踪

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  8. 【Android Studio安装部署系列】四十、Android Studio安装Statistic插件(统计项目总行数)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio 是没有提提供统计代码全部行数的功能的,但是对于开发者来说,这个功能确实必备的,Statistic统计代 ...

  9. 常见的Python脚本

    1.冒泡排序 lis = [56,12,1,8,354,10,100,34,56,7,23,456,234,-58] def sortport(): for i in range(len(lis)-1 ...

  10. Node.js 命令行工具的编写

    日常开发中,编写 Node.js 命令行工具来完成一些小任务是很常见的操作.其编写也不难,和日常编写 Node.js 代码并无二致. package.json 中的 bin 字段 一个 npm 模块, ...