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

use*_*812 2 javascript

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

说我有以下代码:

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

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

在此输入图像描述

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

T.J*_*der 22

类型安全是一个复杂的主题,并没有人就"类型安全"语言究竟是什么达成一致意见.但几乎任何定义都没有,不,JavaScript不是类型安全的.:-)在那个特定的例子中,JavaScript确实提供了运行时类型安全性:它实际上并没有尝试调用i并导致某种内存访问异常或类似情况; 相反,当你的代码试图调用它时,JavaScript引擎所做的第一件事是检查它是否可调用,因为它不是,它引发了一个保护性错误.

但是,类型安全语言试图通过类型实施(在编译/解析阶段和代码运行时)来阻止或防止由于使用不正确的类型而导致的错误或不期望的行为.JavaScript主要不这样做(尽管如此); 一般来说,JavaScript倾向于强制改为.

例如,在类型安全的语言中,这可能会失败:

console.log("hi there" * 4);
Run Code Online (Sandbox Code Playgroud)

...假设*不是字符串的定义运算符.(我相信至少有一种语言,它会导致"hi therehi therehi therehi there").

但是在JavaScript中,*字符串没有定义的含义.但不是导致错误(在编译/解析阶段或运行时),字符串被隐式转换为数字n,然后在表达式中使用n * 4.在字符串的情况下"hi there",强制导致值NaN("不是数字")而不是导致错误(然后NaN * 4也导致NaN).

类型安全语言通常(虽然我并不总是这么认为)具有类型化变量/参数/属性和类似,并且至少在编译/解析阶段进行某些类型检查,而不是在相关代码运行时进行.在那些语言中,i会有一个与之关联的类型(例如,int i而不是var i),并且试图将其作为函数调用的代码在编译/解析阶段会失败,而不是在它运行时失败. JavaScript的.另一方面,JavaScript根本没有类型化的变量/参数/属性.变量可以将对象保持一个时刻,将原始数字保存到下一个.

其中一个好处是JavaScript对鸭子打字很友好(如果它看起来像鸭子和庸医像鸭子,它是鸭子).例如,假设您有一个函数,从概念上讲,它需要一个字符串:

function capitalize(str) {
    return str.charAt(0).toUpperCase() + str.substring(1);
}
Run Code Online (Sandbox Code Playgroud)

在JavaScript中,以下代码调用它:

capitalize(42);
Run Code Online (Sandbox Code Playgroud)

完全正确,并且在编译/解析包含该调用的代码时不会引发任何错误.但是在调用代码时引发错误 - 不是因为42不是字符串(它不是,但这不是重点),而是因为42没有charAt方法.

在具有静态类型安全性的语言中(例如,编译/解析阶段类型安全性),存在与str参数相关联的类型信息,并且错误将在编译/解析代码时.

但是在JavaScript中,不仅很高兴编译/解析该代码,而且很高兴在非字符串上运行它,只要你提供它符合这些标准:

  1. 它有一个charAt方法,用方法返回一些东西toUpperCase,和

  2. 它有一种substring方法.

只要你给它一些符合这些标准的东西,无论那个东西是不是字符串,它都会起作用.

function capitalize(str) {
    return str.charAt(0).toUpperCase() + str.substring(1);
}

var thingy = {
    charAt: function() {
        return {
          toUpperCase: function() {
            return 40;
          }
        }
    },
    substring: function() {
        return 2;
    }
};

console.log(capitalize(thingy)); // 42
Run Code Online (Sandbox Code Playgroud)

;-)

  • 这个答案结尾的例子很美. (8认同)
  • 正如您自己提到的,您在这里谈论的是*静态类型安全*。正如我在回复中所讨论的那样,我更喜欢对*类型安全*进行更广泛的定义。有了这个定义,Javascript 确实是一种类型安全的语言。 (2认同)

And*_*dru 7

Javascript(与JavaRubyHaskell 一起一种类型安全的语言(而C不是)。

另一方面,JavaScript保证静态编译时)类型安全,这是不同的(由@tj-crowder answer描述)。


简而言之,它表示如果一种语言总是对任何代码段都有有用的答案,那么它就是类型安全的

免费书籍Why Rust陈述了以下内容(第 4 页):

类型安全语言 [...] 为每个操作分配一个含义,即使该含义只是引发异常。

而你得到的类型错误正是你操作的意义。

相比之下,C不是类型安全的(尽管它在编译时检查代码),因为您可以创建不会抛出异常的情况,而只是做一些随机的事情。(有关示例,请参见Why Rust书的第3 页和第4 页)Javascript 中存在的隐式类型强制(例如将数字 1转换为字符串 1以进行字符串连接:)1 + '2'是一个定义明确的操作。

为什么锈病书定义明确的按以下方式:

如果一个程序的编写使得任何可能的执行都不能表现出未定义的行为,我们就说该程序是明确定义的

使用定义良好的定义继续:

如果一种语言的类型系统确保每个程序都定义良好,我们就说该语言是类型安全的

这个关于类型安全的说明也很有趣:

请注意,类型安全与语言是在编译时还是在运行时检查类型无关:C 在编译时检查,并且不是类型安全的;Python 在运行时检查,并且是类型安全的。任何实用的类型安全语言都必须在运行时至少进行一些检查(例如数组边界检查)。


有点讽刺的是,一本关于 Rust 的书帮助我更好地理解了 Javascript!

  • 这是我之前遇到的“类型安全”的定义:不存在可能导致将一种类型表示为另一种类型的底层数据的误解的未定义行为。具有强制规则的脚本运行时并不是误解;而是具有强制规则的脚本运行时。事实上,这是类型安全的一个实际例子。我看到维基百科提出了一些非常不同(而且非常模糊)的东西,所以我想这个定义可能不像我想象的那么普遍?看起来很像人们将类型安全(这是相当普遍的)与静态类型混合在一起...... (2认同)
  • @分号 正确。这种“类型安全”和“静态类型”的常见混淆(如 @tj-crowder 的回复)让我很困惑,直到我最终读到 Rust 书,阅读了一个最终完全有意义的定义。 (2认同)