Appearance
发现问题
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 只真正提供动态类型——运行代码看看会发生什么。
另一种方法是使用静态类型系统在运行之前预测预期的代码。