2016-09-22 103 views
1

我读过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是一种类型安全的语言吗?

+0

类型安全,因为在JS会自动转换一些东西,以适合你的不同类型,例如'alert('himom'+ 42)'会输出'himom42',即使“string + integer”没有数学意义。 –

+0

那么一个整数不是一个函数,如果没有指出这个事实的错误,你预期会发生什么? –

+1

Javascript具有动态类型安全性,换句话说,它在运行时引发一些TypeError异常。通常'类型安全语言'是一个术语,用于表示在代码执行之前进行验证。 – Jaco

回答

14

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也导致NaN)。

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

其中一个好处是JavaScript对鸭子打字(如果它看起来像一只鸭子,嘎嘎叫鸭子,它是一只鸭子)。举例来说,假设你有一个函数,理论上,需要一个字符串:

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

在JavaScript中,下面的代码调用它:

capitalize(42); 

是完全正确的,不会引起任何错误时,包含该调用的代码被编译/解析。但它在调用代码时引发错误  —不是因为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

;-)

+4

这个答案最后的例子是美的东西。 – Jamiec

+0

这是一个鸭子打字的例子吗?实际类型无关紧要;只是它符合来电者的标准。 – Carcigenicate

+0

@Carcigenicate:我的'大写'例子是,是的。但是由于缺乏类型安全性,使得'capitalize'不能被声明为只接受一个字符串,而不是一个对象。 (虽然类型安全性有点不同,但如果只有一种类型的“对象”,您可以使用类型安全的语言进行鸭式输入。) –

1

这种类型的错误在运行时有发生,虽然,没有编译时间。

很明显,如果您尝试将某个数字作为函数处理,它在某些时候会失败。

在安全的语言中,它会捕捉到在编译过程中不好的代码永远无法在运行时首先运行失败。

+0

那么解释型语言永远不可能是类型安全的,只有编译语言才可以? – user4582812

+0

@ user4582812:否,解释型语言可以是类型安全的。只是在解析阶段出现与类型相关的错误,而不是等待有问题的代码行被执行。在一个类型安全的解释语言中,如果该行从未执行,您仍然会得到错误(解析过程中)。但在非类型安全的解释型语言中,如果行从未执行,则不会出现错误。 –

+0

我假设通过*“解析阶段”*您的意思是一个阶段,在执行之前,代码检查类型错误。我有一个相关的问题:可以使用动态类型语言(一种允许在运行时更改变量类型的语言)是类型安全的吗? – user4582812