JavaScript是一种类型安全的语言吗?

时间:2016-09-22 15:19:08

标签: javascript

我已经读过JavaScript不是一种类型安全的语言,但我不确定它是多么真实。

说我有以下代码:

<script>
    var i = 123;  // i is an int
    i();  // treat i as a function (this will produce an error)
</script>

当我运行此代码时,我收到以下错误:

enter image description here

所以基本上我不允许将int变量视为函数,这是否意味着JavaScript是一种类型安全的语言?

3 个答案:

答案 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中,不仅编译/解析代码很乐意,而且很高兴在非字符串上运行它,只要你提供它符合这些标准:

  1. 它有一个charAt方法,可以使用str方法返回一些内容,

  2. 它有charAt方法。

  3. 只要你给它一些符合这些标准的东西,无论那个东西是不是字符串,它都会有效。

    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!