JavaScript 类型系统

TypeScript 是一门基于JavaScript之上的一门语言,它重点解决了JavaScript语言类型系统的不足。使用TypeScript可以大大提高代码的可靠程度。

接下来学习的不止是TypeScript这个语言,因为我们要学习的目标是JavaScript语言自有类型系统的问题,以及如何借助一些优秀的技术方案去解决这个问题,而TypeScript是学习过程中涉及到的一门语言。当然到2021年目前为止TS是解决这个问题最终极的方案,所以会着重去学习它。

内容概要:

  • 强类型与弱类型
  • 静态类型和动态类型
  • JavaScript自有类型系统的问题以及问题给我们造成了哪些影响
  • flow静态类型检查方案(小工具,弥补了Js类型系统的不足)
  • TypeScript语言规范和基本应用(基于JavaSc的一门语言)

 

1. 不同类型的区别与意义:强类型与弱类型、静态类型与动态类型

在具体介绍 JavaScript 自有类型系统存在的问题之前,我们先来解释两组在区分不同编程语言时经常提及的名词:强类型与弱类型、静态类型与动态类型。

为什么会通过类型去区分不同编程语言呢?

实际上,我们在区分编程语言时是分别在 类型安全 和 类型检查 两个角度考量的。

类型安全:强类型 vs 弱类型

从类型安全的维度来说,编程语言就分为两种 强类型 vs 弱类型,

这种强弱类型的概念最早是在1974年,美国两位计算机专家提出的,当时对强弱类型的定义是:强类型 在语言层面限制函数的实参类型必须和形参类型一致。弱类型在语言层面则不会限制实参的类型即便函数需要的参数类型和实参的数据类型不一致在语法上也不会报错,在运行上可能会报错

由于强弱类型的定义区分根本不是某一个权威机构的定义,而是几个专家所陈述出的概念,这就导致了后人对强弱类型界定的细节上出现了不一样的理解,但大家都相同描述了强类型具有更强的类型约束,而弱类型中则几乎没有什么约束。

在目前比较主流的一个说法是:强类型语言中不允许有任意的隐式类型转换。弱类型语言中则允许有任意的隐式类型转换。

例如在JavaScript中 , 就允许任意的隐式类型转换:

// (JavaScript)弱类型 - 数据会做隐式的类型转换 
console.log('100' - 50) // 50 
console.log(Math.floor(true)) // 1

当然有些时候也会发现在JavaScript中调用某些方法时也会报出类型错误,比如:

在nodeJs环境下,使用path模块的dirname方法去获取路径中的文件夹路径, 这个方法接收的参数是一个字符串,如果我们传入的不是字符串就会报出一个类型错误

这并不意味这JS就是强类型语言,因为我们所说的强类型是从语言的语法层面限制不允许传入不同类型的值,如果传入的是不同类型的值在编译阶段就会报出错误而不是在运行阶段再通过逻辑判断 去限制。

在JavaScript中所有报出的类型错误都是在代码层面, 在运行时通过逻辑判断然后手动抛出的。

注意:变量类型允许随时改变的特点不是强弱类型的差异,Python 中的变量就允许随时修改类型,但它是强类型的语言。

类型检查 ---------- >动态类型 vs 静态类型

在类型检查的维度,还可以将编程语言分为静态类型语言 vs 动态类型语言

 静态类型语言 和 动态类型语言之间的差异并没什么争议,大家都很统一。

静态类型语言:一个变量在声明时,它的类型就是明确的,而且声明后类型就不可以被修改了。 

动态类型语言:在运行阶段才能够明确变量的类型,而且变量的类型也可以随时发生变化。

例如在JS中: 

var foo = 100;    //运行到这里 才会明确foo变量的类型是number 
foo = 'bar';      //运行到这里 会将它的类型变为字符串
console.log(foo)

所以也可以说,动态类型语言的变量是没有类型的,变量当中存放的值才是有类型的。

所以JavaScript是一门标准的动态类型语言。

总结:

1.从类型安全的角度来说,可以将编程语言分为强类型语言和弱类型语言,它们的区别是 是否允许任意的隐式类型转换。

2.从类型检查的角度来说,可以将编程语言分为静态类型语言和动态类型语言,它们的区别是 是否允许随时修改变量的类型。

3.需要注意的是,我们不能混淆了类型安全和类型检查这两个区分维度,更不能认为弱类型就是动态类型,强类型就是静态类型。

弱类型的问题

接下来我们看一些JavaScript这种弱类型语言在应对大规模应用开发时有可能会遇见的一些常见问题。(虽然只有3个例子,也能充分反映问题)

1.定义一个空对象,然后调用它的foo方法,很明显,空对象里面并没有这个foo方法,但在语言层面上这样写却是可行的。只是把它放到环境中运行时会报类型异常的错误。

而如果obj.foo方法不是立即执行,而是在程序运行后的某个时间点才开始执行。那这个隐患就会留在我们的代码当中。

如果是强类型语言,在我们调用这个不存在的方法,不用等到代码运行时,在语法上就会报出错误。

const obj = {}
obj.foo()
//TypeError: obj.foo is not a function
setTimeout(()=>{
    obj.foo()
},1000000)

弱类型语言只能在运行阶段才能够发现代码中存在的类型异常,而如果在测试时也没有运行到那行代码,那么这行代码带来的隐患就会留在代码当中。

2.这里代码中的 sum 函数因为传入参数类型的不同导致函数的功能发生改变,这就是类型不确定造成的最典型的问题,我们可以通过互相约定来规避这个问题,但约定是根本没有保障的,多人协同开发时我们很难保证所有人能够按照约定去开发。

而如果使用强类型语言,这种情况会被彻底避免掉。因为如果参数传入其他类型的值,在语法上就行不通。

//示例 2
function sum (a, b) {
	return a + b
}
console.log(sum(100, 100))  // 200
console.log(sum(100, '100'))  // 100100

传入的参数类型不明确可能会导致函数的功能发生改变,这就是类型不明确造成的最典型的问题

3.前面说过,普通对象的属性名只能是字符串或者Symbol类型。但因为JavaScript是弱类型语言,所以在索引器中使用任意类型的数据作为属性名,在它内部会自动通过toString方法转换为字符串。 

在强类型的情况下,这里索引器会有明确的类型要求,不满足类型要求的成员在语法上就行不通。

// 示例 3
const obj = {}
obj[true] = 100
console.log(obj['true'])  // 100

综上,弱类型这种语言的弊端是十分明显的,只是代码量小的情况下我们可以通过约定的方式去规避,而开发周期长的大型项目,这种君子约定的方式仍然会存在隐患,只有在语法层面上做出强制要求才提供更可靠的保障。使用强类型语言可以消灭一大部分又可能存在的异常。不必等到运行时才去慢慢的debug。

 

强类型的优势

  • 错误更早暴露。编码阶段能够提前消灭一大部分有可能会出现的类型异常,不用等到运行阶段才发现。
  • 代码更智能,编码更准确。JavaScript 的智能提示很多时候是没有办法准确提示出有用的内容,很多时候是无法推断我们声明的变量究竟是什么类型的。强类型语言则时时刻刻都能够知道我们的变量是什么类型的,推断提示自然会更准确,开发时更有效率。
  • 重构更牢靠。在重构代码时我们总会去修改或删除一些代码,在 JavaScript 中去这样做我们无法保证重构后的代码是否存在其它引用导致异常发生。强类型的话在重构后的编译时就会发现这种异常。
  • 减少不必要的类型判断代码,因为不是我们所需要的类型数据根本不会传递进来。

JavaScript类型系统特征

由于JavaScript是一门弱类型、动态类型语言。语言本身的类型系统是非常薄弱的。甚至也可以说JavaScript根本没有类型系统。

这种语言用一个比较流行的词来说就是'任性',因为它几乎没有任何的类型限制。所以它是非常灵活多变的,在这种灵活多变的表象背后,丢失掉的就是类型系统的可靠性。我们在代码当中每每遇到一个变量或者形参都会担心它到底是不是我们想要的类型,用另外一个词来说,就是'不靠谱'。

那为什么JavaScript为什么不能设计成一种强类型。的静态类型的更靠谱的语言呢?

1.原因与JavaScript的背景有关:早期它根本不会想到JavaScript的应用会发展到今天的规模。它早期的应用非常简单,很多时候几十行,几百行代码就全部搞定了,一眼就能看到头的情况下,类型系统就会显得很多余。

2.JavaScript是一门脚本语言,脚本语言的特点就是不需要编译,直接在运行环境中去运行。 换句话说:JavaScript没有编译环节。所以即便把它设计为静态类型语言也是没有用的,因为静态类型语言需要在编译阶段做类型检查。

所以JavaScript就成为了更灵活的 弱类型/动态类型语言。

放在当时的环境中,这并没有声明问题,甚至可以说这些特点是JavaScript的一大优势。

但现如今,前端应用的规模已经完全不同,遍地都是一些大规模的应用。JavaScript代码也会越来越多,开发周期也越来越长。所以在大规模应用下,之前JavaScript弱类型/动态类型这一特点的优势,也就变成了它的短板。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值