📜  JS++ |字段和方法

📅  最后修改于: 2022-05-13 01:55:37.375000             🧑  作者: Mango

JS++ |字段和方法

创建和渲染动物

打开 'src/Animals/Cat.jspp' 并输入以下代码:

external $;

module Animals
{
    class Cat
    {
        void render() {
            var $element = $(
                """
                
""" ); $("#content").append($element); } } }

您可能会立即注意到的一件事是多行字符串(“”“...”“”)。当我们用三引号将字符串括起来时,我们可以写一个“多行”字符串。多行字符串是 JS++ 的一个特性,在处理 HTML 时特别有用。您会注意到,对于多行字符串,我们不必转义我们的双引号字符(") 或字符。

除了多行字符串,我们只是像往常一样通过 $(...) 将一些 HTML 传递给 jQuery。 jQuery 会将其识别为 HTML 并为我们动态创建 HTML 元素。但是,动态创建的 HTML 元素仍然只保存在内存中,除非我们将其渲染到页面。我们用这条线做到这一点:

$("#content").append($element);

您会注意到我们将 jQuery 元素的变量命名为 $element。使用 $ 符号为保存 jQuery 对象的变量添加前缀是一种常见的命名约定。

您可能还注意到我们将 jQuery $element 变量的数据类型声明为“var”。正如我们在前几章中所讨论的,对于复杂对象可能并不总是有对应的 JS++ 数据类型,因此我们可以在这些情况下使用“var”(或者甚至只是为了方便)。

旁注:用于操作网页的 jQuery 和文档对象模型 (DOM) API 可以归类为“高度动态的”。一些大公司在这些情况下尝试添加静态数据类型是错误的,因为在许多极端情况下静态数据类型将不正确或失败 - 例如对于包含 DOM API 的 ECMAScript“宿主对象”,其中“实现-定义的”行为,例如相同 DOM API 方法的不同浏览器实现,根据语言规范是有效的(并且确实发生在现实世界的实现中)。另一个例子是 Internet Explorer 版本中的垃圾收集器实现,其中 GC 可以过早回收非循环、正在使用的主机对象(例如用于实时流的“htmlfile”ActiveXObject),这种情况不适合进行静态分析。尽管它们很方便,但这些情况下的静态数据类型会产生“虚假的安全感”。但是,对这些主题的讨论超出了本教程的范围。

您会注意到我们“Cat”类中声明了一个函数。在类中声明的函数通常称为“类方法”或简称为“方法”。不是类成员的函数称为“自由函数”。

我们在模块中声明了一个类,所以这个文件本身不会编译。我们需要创建一个“主文件”作为程序入口点。在您的“src”文件夹(“Animals”文件夹的父文件夹)中,您会记得我们创建了一个空的 main.jspp 文件。打开 main.jspp 文件并输入以下代码行:

import Animals;

Cat cat = new Cat();
cat.render();

我们首先实例化该类以获得一个类实例。一旦我们有了一个类实例,我们就在那个特定的类实例上调用“render”方法。

编译

由于我们的深层目录结构,与我们之前的教程示例相比,编译会略有不同。 Mac/Linux 用户不需要做太多调整,但对于 Windows 用户,我们必须开始使用命令提示符。

对于 Mac/Linux 用户,只需打开终端到“OOP”代码文件夹并输入以下命令:

$ js++ src/ -o build/app.jspp.js

对于 Windows 用户,打开命令提示符。导航到 OOP 'code' 文件夹的目录(使用 'cd' 命令)。导航到文件夹后,我们输入与 Mac/Linux 用户相同的命令:

> js++ src/ -o build/app.jspp.js

如果一切正常,您应该会看到一个绿色的“OK”,如上面的屏幕截图所示(适用于所有操作系统:Windows、Mac 和 Linux)。

在您的网络浏览器中打开 index.html(在根“OOP”文件夹中)。您应该会看到一个小猫图标呈现到页面:

造型动物

现在,我们的猫很小,很难看到。让我们修改样式,使我们的猫更大更清晰。

在“style”文件夹中打开 style.css。它应该是空的,但我们将添加一个简单的 CSS 规则以使我们的猫更清晰:

.animal i { font-size: 50px; }

保存 style.css 并刷新 index.html。你应该看到一只更大的猫。

类字段

除了定义类行为的方法之外,类还可以保存自己的数据。从本质上讲,您可以将类视为数据以及对该数据进行操作的方法。例如,对于像猫这样的宠物,我们可能希望能够给猫起一个名字。名称是数据,方法的示例可能是允许我们设置或更改名称的函数。

类字段允许我们指定类独有的数据。字段只是变量声明:

class Cat
{
    string name;
}

类字段与常规变量声明不同,因为它们只能通过类或类实例访问。此外,我们声明了一个类实例独有的“名称”字段;这意味着类的每个唯一实例都将拥有自己唯一的名称数据。

特定实例独有的数据可能非常有用,尤其是在处理大量相似对象时。但是,我们当前将猫呈现到页面的代码实际上并没有保持实例唯一的数据!让我们观察;将 main.jspp 代码更改如下,以再次调用 render():

import Animals;

Cat cat = new Cat();
cat.render();
cat.render();

编译代码并打开 index.html。您应该看到渲染了两只猫,但我们只有一个“猫”类的实例。这并不理想;相反,如果我们想在页面上渲染两只猫,我们应该需要两个 'Cat' 实例。为此,我们必须检查我们的 render() 代码:

class Cat
{
    void render() {
        var $element = $(
            """
            
""" ); $("#content").append($element); } }

你看到有什么问题吗?

每次调用 render() 方法时,我们都在调用 jQuery 来创建一个新对象,然后我们通过 jQuery 的 append() 方法将该新对象渲染到页面。我们需要做的是让页面元素的创建只针对类实例。我们可以通过简单地将 render() 中的变量声明移动到类字段来做到这一点。这是我们的完整代码:

external $;

module Animals
{
    class Cat
    {
        var $element = $(
            """
            
""" ); void render() { $("#content").append($element); } } }

除了将变量声明从 render() 移动到类本身之外,我们在上面的代码中什么也没做,所以它变成了一个字段。现在,只有在我们实例化类时才会初始化该字段。换句话说,您看到的将 HTML 转换为 jQuery 对象的 jQuery函数调用在我们使用“new”关键字实例化我们的类之前不会被执行。

通过对同一类实例的两个 render() 调用,使您的代码与您的代码完全相同。但是,使用更新的 Cat.jspp,再次编译您的代码。打开 index.html。您应该只看到一只猫呈现到页面上。

现在让我们尝试通过更新 main.jspp 以使用两个类实例来创建两只猫:

import Animals;

Cat cat1 = new Cat();
cat1.render();
Cat cat2 = new Cat();
cat2.render();

您现在应该看到两只猫,每个类实例一只:

用字段和方法命名我们的动物

虽然我们的第一个类字段示例涉及命名,但我们实际上从未向我们的类添加名称字段。然而,不仅仅是命名我们的猫,当我们将鼠标悬停在动物上时,让我们通过在网络浏览器中显示名称来使其有形。正如我们在前面的示例中所展示的,像名称这样的字段对于类实例应该是唯一的——如果页面上的两个 cat 元素被赋予不同的名称,则它们不应显示相同的名称。

将以下代码插入 Cat.jspp:

external $;

module Animals
{
    class Cat
    {
        string name;

        var $element = $(
            """
            
""" ); void setName(string name) { this.name = name; } void render() { $("#content").append($element); $element.attr("title", name); } } }

我们添加了一个新字段:“名称”,类型为“字符串”。我们还添加了一个新方法“setName”。它只包含一行代码:

this.name = name;

您会注意到该方法采用一个名为“name”的参数:

void setName(string name) {
    this.name = name;
}

为了从我们的“name”类字段中消除“name”参数的歧义,我们需要使用“this”。当两个冲突的名称出现在同一个方法中时,这被称为“变量阴影”。这是一种方便,因此我们不必想出不同的变量名称来描述相同的概念。因此,我们的声明是:将“name”类字段(“this.name”)设置为作为参数传入我们方法的“name”值。

类中的“this”关键字指的是类实例。类实例方法,如我们刚刚定义的 'setName' 方法,除非先实例化了类,否则无法调用。一旦我们实例化了“Cat”类,我们就可以调用“setName”方法。当我们调用“setName”实例方法时,“this”关键字指的是执行该方法的类实例。因此,上面的语句将设置正在执行“setName”的类实例的“name”字段;它对于类实例总是唯一的;因此,在“setName”方法调用之后,没有两个类实例最终会设置相同的“name”字段。

最后,我们在 'render' 方法中添加了以下语句:

$element.attr("title", name);

这将设置我们呈现给页面的 cat HTML 元素的 HTML 'title' 属性。通过设置 'title' 属性,我们可以设置当我们将鼠标悬停在 HTML 元素上时出现的文本。在这种情况下,当我们将鼠标悬停在 cat 元素上时,我们将看到它的名称。

在我们看到我们的结果之前,我们必须在 main.jspp 中设置我们的猫的名字。让我们这样做:

import Animals;

Cat cat1 = new Cat();
cat1.setName("Kitty");
cat1.render();
Cat cat2 = new Cat();
cat2.setName("Kat");
cat2.render();

确保在 'render' 方法之前调用 'setName'。

编译代码。再一次,对于 Windows、Mac 和 Linux 用户,命令现在都是一样的:

$ js++ src/ -o build/app.jspp.js

如果程序编译成功,打开 index.html。将你的名字悬停在每只猫上。你应该看到它的名字。