我已经读过JavaScript不是一种类型安全的语言,但我不确定它是多么真实。
说我有以下代码:
<script>
var i = 123; // i is an int
i(); // treat i as a function (this will produce an error)
</script>
当我运行此代码时,我收到以下错误:
所以基本上我不允许将int
变量视为函数,这是否意味着JavaScript是一种类型安全的语言?
答案 0 :(得分:19)
Type safety是一个复杂的主题,并没有人就“类型安全”语言究竟是什么达成一致意见。但几乎任何定义都没有,不,JavaScript不是类型安全的。 :-)在那个特定的例子中,JavaScript确实提供了运行时类型的安全性:它实际上并没有尝试调用i
并导致某种类型的内存访问异常或类似情况;相反,当你的代码试图调用它时,JavaScript引擎所做的第一件事是检查它是否可调用,并且由于它不是,它引发了一个保护错误。
但是,类型安全语言试图通过类型实施(在编译/解析阶段和代码运行时)来阻止或防止由于使用不正确的类型而导致的错误或不良行为。 JavaScript主要不这样做(尽管如此);一般来说,JavaScript倾向于强制改变。
例如,在类型安全的语言中,这可能会失败:
console.log("hi there" * 4);
...假设*
不是字符串的定义运算符。 (我相信至少有一种语言可以产生"hi therehi therehi therehi there"
)。
但是在JavaScript中,*
没有字符串的定义含义。但是不是导致错误(在编译/解析阶段或运行时),字符串被隐式转换为数字 n ,然后在表达式n * 4
中使用。对于字符串"hi there"
,强制会产生值NaN
(“不是数字”)而不是导致错误(然后NaN * 4
也会导致{{1} })。
类型安全语言通常(尽管我并不总是这么认为)具有类型化的变量/参数/属性和类似,并且至少在编译/解析阶段进行某些类型检查,而不是在相关代码运行时进行。在这些语言中,NaN
会有一个与之关联的类型(例如,i
而不是int i
),并且试图将其称为函数的代码在编译时会失败/解析阶段,而不是像在JavaScript中那样运行它。另一方面,JavaScript根本没有类型化的变量/参数/属性。变量可以将对象保持一个时刻,将原始数字保存到下一个。
这样做的好处之一是JavaScript对 duck-typing 很友好(如果它看起来像鸭子,像鸭子那样嘎嘎叫,它就是鸭子)。例如,假设您有一个函数,从概念上讲,它需要一个字符串:
var i
在JavaScript中,以下代码调用它:
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.substring(1);
}
是完全正确的,并且在编译/解析包含该调用的代码时不会引发任何错误。但是当调用代码时将引发错误 - 不是因为42不是字符串(它不是,但这不是重点),而是因为42没有{{ 1}}方法。
在具有静态类型安全性的语言中(例如,编译/解析阶段类型安全性),会有与capitalize(42);
参数关联的类型信息,并且错误将在编译/解析代码时出现。
但是在JavaScript中,不仅编译/解析代码很乐意,而且很高兴在非字符串上运行它,只要你提供它符合这些标准:
它有一个charAt
方法,可以使用str
方法返回一些内容,
它有charAt
方法。
只要你给它一些符合这些标准的东西,无论那个东西是不是字符串,它都会有效。
toUpperCase
- )
答案 1 :(得分:1)
该类型错误在运行时发生,而不是编译时。
显然,如果你试图将一个数字视为一个函数,它会在某些时候失败。
在一种安全的语言中,它会在编译期间捕获到这一点,因此错误的代码永远不会在运行时首先运行失败。
答案 2 :(得分:0)
Javascript (与 Java , Ruby , Haskell 一起)是类型安全语言(而 C 不是)。
简单地说,如果某种语言总是对任何一段代码都有用,那么它就是类型安全。
免费书Why Rust指出以下内容(第4页):
类型安全的语言[...]为每个操作分配一个含义,即使该含义仅仅是引发异常。
您得到的类型错误正是操作的含义。
相反, C 不能键入安全类型(尽管它在编译时检查代码),因为您可以创建一些情况,使其不会抛出异常,而只是随机执行。 (有关示例,请参见《为什么要生锈》的第3和第4页)
Javascript中存在的隐式类型转换(例如,将数字1强制转换为字符串1以进行字符串连接:1 + '2'
)是定义明确的操作。
为什么Rust 本书通过以下方式定义了定义明确的:
如果编写了程序,使得任何可能的执行都不会表现出 undefined 行为,则我们说该程序定义良好。
使用定义明确的定义继续进行:
如果一种语言的类型系统确保每个程序的定义都正确,那么我们就说该语言是类型安全。
关于类型安全性的注释也很有趣:
请注意,类型安全主要取决于语言是在编译时还是在运行时检查类型:C在编译时进行检查,而不是类型安全; Python在运行时进行检查,并且类型安全。任何实用的类型安全语言都必须在运行时至少进行一些检查(例如,数组边界检查)。
讽刺的是,有关Rust的书帮助我更好地理解了Javascript!