Skip to content

发现问题

avaScript 中的每个值都有一组行为,可以通过运行不同的操作来观察。这听起来很抽象,来举一个简单的例子,考虑可能对名为 message 的变量运行的一些操作:

javascript
// 在 'message' 上访问属性 'toLowerCase',并调用它 
message.toLowerCase(); 
// 调用 'message' 
message();

第一行可运行的代码访问一个属性 toLowerCase ,然后调用它。第二个尝试 message 直接调用。 但是假设不知道 message 。这很常见——我们无法可靠地说出尝试运行任何这些代码会得到什么结果。每个操作的行为完全取决于我们最初给 message 的赋值。

  • 可以调用 message 吗?

  • 它有 toLowerCase 这个属性吗?

  • 如果能, toLowerCase 可以调用吗?

  • 如果这两个值都是可调用的,它们返回什么?

这些问题的答案通常是我们在编写 JavaScript 时牢记在心的东西,我们必须希望所有细节都正确。假设 message 按以下方式定义

javascript
const message = "Hello World!";

如果我们尝试运行 message.toLowerCase() ,会得到相同的小写字符串。 那第二行代码呢?如果熟悉 JavaScript,就会知道这会失败并出现异常:

javascript
TypeError: message is not a function

如果能避免这样的错误,那就太好了。 当运行代码时, JavaScript 运行时选择做什么的方式是通过确定值的类型——它具有什么样的行为和功能。这 TypeError 就是暗指的一部分- 它说字符串 "Hello World!" 不能作为函数调用。 对于某些值,例如基本类型 string 和 number ,我们可以在运行时使用 typeof 运算符识别它们的类型。但是对于函数之类的其他东西,没有相应的运行时机制来识别它们的类型。例如,下面这个函数:

javascript
function fn(x) { return x.flip(); }

我们可以通过阅读代码观察到这个函数只有在给定一个具有可调用 flip 属性的对象时才能工作,但是 JavaScript 并没有以我们可以在代码运行时检查的方式来显示这些信息。在纯 JavaScript 中,告诉 fn 特定值做什么的唯一方法是调用它并查看会发生什么。这种行为使得在运行之前很难预测代码会做什么,这意味着在编写代码时更难知道代码会做什么。

这样看来,类型是描述可以传递给 fn 哪些值会崩溃的概念。JavaScript 只真正提供动态类型——运行代码看看会发生什么。

另一种方法是使用静态类型系统在运行之前预测预期的代码。