一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
前言
什么是类型系统?
类型系统用于将编程语言中的数值和表达式归类为许多不同的类型,并且定义这些类型是如何运作的。类型可以用来表示某样东西有着具体的意义或者目的
类型系统再不同的语言之间有着很大的差异,并且主要分为 结构化类型 和 标称类型。
本文主要介绍一下 Typescript 使用的结构化类型系统,它和我们经常听见的鸭子类型也有着很深的关系。
什么是标称类型
像我们比较常接触到的 java 语言,就是一门 标称类型语言,在我的理解当中,标称类型就是比较看重于数据之间的继承关系,哪怕你有两个类型,比如说你定义了 人类 他有着 名字,性别,年龄。你又定义了 狗狗 ,它也有名字,性别,年龄。这在java中是不会承他们两个之间相等的,人就是人,狗就是狗,虽然他们有着一样的属性,但是他们的本质上是不一样的,这就是 标称类型语言。
那么在标称类型语言中,这两个对象不相等,在结构化中就相等吗,这个我们接下来慢慢说道。
什么是鸭子类型
概念
要解释结构化类型,那么首先就需要先来了解一下什么是鸭子类型,相信有一句话,应该很多人都听到过:
如果它看起来像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那它很可能就是鸭子。
鸭子类型语言使用鸭子测试来评估一个对象是否是某一个类型,上面这句话就是对鸭子测试的一个概括。
那么在这里我们回到上面的那个问题,在鸭子类型当中,如果一个人有着和狗相同的属性,那么他们相等吗?
答案是肯定的,如果两个对象的属性完全相等,那么在鸭子类型看来,他们都是一样的。比如说人类会走会跑会跳,但是狗狗也会走会跑回跳,那么鸭子类型就没办法区分他们两个,你必须定义一个独有的属性
比方说我们给人类加上了说话这个方法,但是狗狗中是没有的,那么就可以通过这个方法,来推测一个对象他是人类还是狗狗。
那么我们最常见到的 JavaScript 就是典型的 鸭子类型语言,我们接下来来举一个 JavaScript 中的简单例子,来说明一下鸭子类型是怎么一个鸭子法。
JavaScript 例子 之 Array.from()
有使用过 Array.from() 的小伙伴,应该知道,这个方法可以把字符串转化为数组,当然,不止是字符串可以做一个转化,还有伪数组对象或可迭代对象。
那么这些都是说明意思呢,和鸭子类型又有着什么关系,让我们先来一个简单的例子:
使用 Array.from() 转化字符串没有问题
这里我们转化一个对象,对象中有着一个length属性,我们会发现, Array.from() 也会帮我们把它转化为数组,相信到这里就会发现了鸭子类型的含义,对于 Array.from() 这个方法来说,它不管你是什么但是只要你身上有length这个属性他就会认为你是可以转化的。
这也就是之前说到的鸭子类型的含义,只要你会嘎嘎叫,我就当你是一只鸭子。
但是鸭子类型不存在编译器,语言再提供给我们很大的灵活性的同时,也造成了非常容易产生的运行时错误,这时候,结构化类型语言就出现了。
结构化类型
Typescript 就是一门使用了结构化类型系统的语言,在鸭子类型的基础上保留了它的特性,但是新增了编译期用于检测程序的完整性,这也就说明,其实 结构化类型 的根本还是鸭子类型,只不过是新增了一个编译时来防止运行时发生部分错误。
那么 Typescript 的结构化类型既然是在 鸭子类型的基础之上,那么 Typescript 的类型准则就也是一样的,类型 a 如果需要兼容类型 b,那么 b 中至少要有和 a 相同的属性。
interface Person{
name:string;
age:number;
}
function speak(e:Person){
console.log('Hello,' + e.name)
}
let xiaoming = {
name:'xiaoming',
age:13 ,
sex:1,
}
greet(y) // Hello,xiaoming
在例子当中,虽然小明有着三个属性,但是只要你有 name 和 age,那么就认为他是一个人类,这样哪怕是多了一个性别属性,也是不会出错的,这就也是鸭子类型的一个表现。
总结
本文主要讲述了 前端 接触最多的鸭子类型,当然 Typescript 的结构化类型系统本质上也是一种鸭子类型,所以要带着鸭子类型的思维去理解 Typescript 的代码,这样才能够更好的去解读一些操作符的实际意义和作用。