JS++ JavaScript中的类型

JS++ JavaScript中的类型

在这一章中,我们将探索JavaScript的编程风格,以及开发者如何在JavaScript中使用类型(而不是Js++)。本章将帮助你理解接下来的章节,这些章节将详细解释JS++类型系统。

在本教程中,我们将使用Google Chrome网络浏览器。如果你还没有谷歌浏览器,请点击这里下载。

为了执行JavaScript代码,我们将使用Chrome开发工具控制台。打开Chrome浏览器,按下Ctrl + Shift + J组合键,选择 “控制台 “标签。

复制并粘贴以下代码到你的控制台,然后按回车键执行。

var message;
message = "This is a test.";
if (Math.random() > 0.5) {
    message = 123;
}
console.log(message);

点击你的 “向上箭头”,并点击 “回车 “来评估代码一次以上。试着对代码进行几次评估。

JS++  JavaScript中的类型

注意上述代码中的数据类型是如何从字符串变为数字的。然而,只有当随机生成的数字大于0.5时,它才 会变为数字。因此,每次执行脚本时,变量’message’的数据类型都可能不同。这在JavaScript中是个大问题。例如,下面的JavaScript代码是不安全的。

function lowercaseCompare(a, b) {
    return a.toLowerCase() == b.toLowerCase();
}

原因是toLowerCase()是一个仅适用于JavaScript字符串的方法。让我们在Chrome控制台中执行以下JavaScript代码。

function lowercaseCompare(a, b) {
    return a.toLowerCase() == b.toLowerCase();
}

console.log("First message.");
lowercaseCompare("10", 10); // Crashes with 'TypeError'
console.log("Second message."); // Never executes.

请注意,脚本会以TypeError的方式崩溃。第二条信息从未被记录下来。关键是代码崩溃的原因是toLowerCase()不是一个可用于数字的方法,但该函数是用一个字符串(”10″)和一个数字(10)调用的。数字参数不是 “lowercaseCompare “函数的有效参数。如果你改变了函数的调用,你会发现程序不再崩溃了。

// Change this:
// lowercaseCompare("10", 10); // Crashes with 'TypeError'
// to:
lowercaseCompare("10", "10");

开发人员在JavaScript中通过先检查类型来解决这些问题。这是在JavaScript中重写上述’lowercaseCompare’函数的比较安全的方法。

function lowercaseCompare(a, b) {
    if (typeof a != "string" || typeof b != "string") {
        return false;
    }

    return a.toLowerCase() == b.toLowerCase();
}

我们使用’typeof’检查类型,如果收到无效的参数类型,我们就返回一个默认值。然而,对于较大的程序来说,这可能会导致 很多 额外的代码,而且可能并不总是有一个适用的默认值。

JavaScript中不宽容的错误

在前面的例子中,我们探讨了JavaScript中一种类型的不可饶恕的错误:导致脚本执行结束的TypeError。有许多其他类型的错误是Js++所防止的,但是,现在我们只看其他一类错误。参考错误(ReferenceErrors)。下面这段JavaScript代码有什么问题?

var message = "This is a test.";
console.log(message);

尝试在你的控制台执行上述代码。再一次,没有任何东西被记录下来。相反,你得到一个ReferenceError。这是因为上面的代码中有一个错字。如果我们修正了这个错别字,代码就会成功。

var message = "This is a test.";
console.log(message);

JavaScript可以因打字错误而失败!TypeErrors和ReferenceErrors不会发生在JS++中。我们把TypeErrors和ReferenceErrors归为 “不可饶恕 “的错误,因为它们会导致JavaScript脚本的执行停止。然而,在JavaScript中还有一种类型的错误更危险,因为它们是 “无声的”。

饶恕JavaScript中的 “沉默 “错误

在JavaScript中有一类 “无声 “的错误,它们可以默默地继续在你的程序中传播。我们称这些为 “宽容的 “错误,因为它们不会停止脚本的执行,但是,尽管名字无害,我们可以认为它们比不宽容的错误更危险,因为它们继续传播。

考虑一下下面这个JavaScript函数。

function subtract(a, b) { return a - b; }

这个函数表面上看起来很简单,但是–随着脚本变得越来越复杂–当变量发生变化并依赖于跨越数千行代码的其他数值时,你可能会意外地从一个最终成为数字的变量中减去一个最终成为字符串的变量。如果你尝试这样的调用,你会得到NaN(不是数字)。

在你的控制台中评估以下代码。

function subtract(a, b) { return a - b; }
subtract("a", 1);

观察产生的NaN(非数字)值。它不会使你的程序崩溃,所以我们称它为宽容的错误,但是错误值会在你程序的其他部分传播,所以你的程序会继续默默地带着错误运行。例如,后续的计算可能依赖于 “减法 “函数返回的值。让我们尝试其他的算术操作来观察。

function subtract(a, b) { return a - b; }
var result = subtract("a", 1); // NaN
console.log(result);
result += 10; // Add 10 to NaN
console.log(result);

没有崩溃,也没有错误报告。它只是默默地带着错误值继续运行。

你将无法运行下面的代码,但这里有一个例子,说明在一个潜在的真实世界场景中,这种错误值如何通过你的应用程序传播,一个购物车后端。

var total = 0;
total += totalCartItems();
while ((removedPrice = removedFromCart()) != null) {
    total = subtract(total, removedPrice);
}
total += tax();
total += shipping();

在上面的例子中,我们的购物车最终可能会出现NaN(非数字)值–导致企业的销售损失,由于没有明确的错误,所以很难发现。

JavaScript的直观性

JS++是基于广泛的JavaScript开发经验而设计的–不仅适用于大型复杂的应用程序,而且适用于 任何 可以使用JavaScript的 地方 --从Windows Script Host的脚本和宏到基于ActiveX的传统程序,以及在一些企业环境中仍然普遍存在的类似程序。简而言之,JS++可以在任何需要使用JavaScript的地方工作–从基本的到复杂的到神秘的。

与JS++相关的一个重要观察是,大多数JavaScript程序已经有了良好的类型(但不是 “完美 “的类型)。回顾一下JavaScript’lowercaseCompare’函数的 “不安全 “和 “安全 “版本。

// Unsafe:
function lowercaseCompare(a, b) {
    return a.toLowerCase() == b.toLowerCase();
}
// Safe: 
function lowercaseCompare(a, b) {
    if (typeof a != "string" || typeof b != "string") {
        return false;
    }

    return a.toLowerCase() == b.toLowerCase();
}

安全版本要繁琐得多,而且–在实践中–大多数JavaScript开发者都会用不安全的方式编写他们的大部分函数。原因是,通过观察函数主体,我们知道预期的参数类型是字符串,因为两个参数都使用了只对字符串有效的 “toLowerCase “方法。换句话说,在JavaScript中,我们只需看一下代码就能对类型有一个 直观的认识

考虑一下下面的变量并猜测它们的类型。

var employeeAge;
var employeeName;
var isEmployed;

employeeAge是一个数字,employeeName是一个字符串,isEmployed是一个布尔值。

现在试着猜测一下以下函数的预期参数类型。

function multiply(a, b) { return a * b; }
function log(message) { console.log("MESSAGE: " + message); }

如果你为’a’和’b’参数提供数字参数,那么函数’multiply’就最有意义。此外,’log’函数对于字符串是最正确的。

JavaScript的强制转换(”类型强制”)

有时,JavaScript程序员不会使用’typeof’来检查类型,而是强制将参数转换为他们需要的数据类型(尤其是在直觉可能失败的情况下)。这种技术是类型强制的一个实例,其结果是代码的容错性更强,因为如果提供的参数的数据类型不正确,它不会以异常退出。

再一次,让我们看看我们如何使用这个想法来改变我们的 “lowercaseCompare “例子。

// Unsafe:
function lowercaseCompare(a, b) {
    return a.toLowerCase() == b.toLowerCase();
}
// Safer: 
function lowercaseCompare(a, b) {
    a = a.toString();
    b = b.toString();

    return a.toLowerCase() == b.toLowerCase();
}

在重新编写的’lowercaseCompare’函数中,我们 “强迫”‘a’和’b’参数被转换为一个字符串。这使得我们可以安全地调用’toLowerCase’方法而不发生崩溃。现在,如果调用’lowercaseCompare’函数,我们得到以下结果。

lowercaseCompare("abc", "abc") // true
lowercaseCompare("abc", 10) // false
lowercaseCompare("10", "10") // true
lowercaseCompare("10", 10) // true

然而,精明的观察者会注意到新版本的’lowercaseCompare’被标记为 “更安全 “而不是 “安全”。

为什么?

toString并不是强制转换为字符串的 最正确 方法。(由于运行时的方法查找,它也不是最快的,但想象一下,在写一行代码时要考虑所有这些细节?在JS++之前,网络编程就是这样的)。

一个例子是,如果我们试图用一个我们忘记初始化的变量调用’lowercaseCompare’,如果我们使用’toString’,它又会崩溃。让我们试试吧。

function lowercaseCompare(a, b) {
    a = a.toString();
    b = b.toString();

    return a.toLowerCase() == b.toLowerCase();
}
var a, b; // uninitialized variables
var result = lowercaseCompare(a, b);
console.log(result); // Never executes

不,相反,对字符串进行类型强制的 最正确 方式是这样的。

// Finally safe: 
function lowercaseCompare(a, b) {
    a += ""; // correct type coercion
    b += ""; // correct type coercion

    return a.toLowerCase() == b.toLowerCase();
}
var a, b;
var result = lowercaseCompare(a, b);
console.log(result);

正确的代码只剩下一个问题:它变得不可读。如果你不得不在你希望表达你想要字符串数据的意图的地方插入+=””,你的代码会是什么样子?

JS++中的’lowercaseCompare’。

现在有很多东西需要消化了用JavaScript写好代码是很难的。想象一下,在用JavaScript写一小段代码时,要考虑到所有这些因素:安全、性能、代码的可读性、不可原谅的错误、沉默的错误、正确性等等。这实际上只触及了JavaScript角落案例的表面,但它为我们提供了足够的信息来开始理解JS++中的类型。

然而,如果我们用Js++写代码,Js++实际上为我们处理所有这些考虑。 这意味着你可以写出可读的代码,但JS++编译器会处理生成快速、安全和正确的代码。

在我们进入下一章–详细解释JS++类型系统–之前,让我们试着用JS++重写 “lowercaseCompare “代码。我们将从故意不正确的代码开始,向你展示Js++是如何及早发现此类错误并告诉你如何修复它们。创建一个’test.jspp’文件并输入以下代码。

import System;

function lowercaseCompare(string a, string b) {
    return a.toLowerCase() == b.toLowerCase();
}

Console.log("First message.");
lowercaseCompare("10", 10);
Console.log("Second message.");

尝试编译该文件。它不会工作。JS++很早就发现了这个错误。

[  ERROR  ] JSPPE5024: No overload for `lowercaseCompare' 
matching signature `lowercaseCompare(string, int)' at line 8 char 0 at test.jspp

它能准确地告诉你错误发生的行,这样你就能在你的用户、访客或客户有机会遇到它之前 ,把它修好。让我们来修复这个错误的行,JS++告诉我们它在第8行。

// lowercaseCompare("10", 10);
// becomes:
lowercaseCompare("10", "10");

在修复了违规的一行后,运行代码。在Windows中,右击该文件并选择 “用JS++执行”。在Mac或Linux中,在终端运行以下命令。

js++ --execute test.jspp

你会看到这两条信息都被成功记录。

在下一章中,我们将通过实例来探索JS++的类型系统和 “类型保证”。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

JavaScript 教程