创建和渲染动物
打开“src/Animals/Cat”。并输入以下代码:
external $; module Animals { class Cat { void render() { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); $("#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可以归类为“高度动态”一些大公司试图在这些情况下添加静态数据类型是不正确的,因为在许多情况下,静态数据类型将不正确或失败——例如对于ECMAScript“主机对象”,其中包括DOM API,“实现定义”行为,例如同一DOM API方法的不同浏览器实现,根据语言规范,它是有效的(并且确实发生在现实世界的实现中)。另一个例子是Internet Explorer版本中的垃圾收集器实现,GC可以过早地回收非循环的、正在使用的主机对象(例如用于实时流的“htmlfile”ActiveXObject),这种情况不适合静态分析。尽管它们很方便,但在这些情况下,静态数据类型会产生一种“虚假的安全感”但是,对这些主题的讨论超出了本教程的范围。
你会注意到我们声明了一个函数 在…内 我们的“猫”课。在类中声明的函数通常称为“类方法”,简称“方法”。非类成员的函数称为“自由函数”
我们在一个模块中声明了一个类,所以这个文件本身不会编译。我们需要创建一个“主文件”作为程序入口点。在“src”文件夹(“Animals”文件夹的父文件夹)中,您会记得我们创建了一个空的main。jspp文件。打开主管道。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)。
开放索引。网页浏览器中的html(在根“OOP”文件夹中)。您应该会看到一个小的cat图标呈现在页面上:
给动物定型
现在,我们的猫很小,很难看到。让我们修改一下造型,让我们的猫更大更清晰。
开放式。“样式”文件夹中的css。它应该是空的,但我们将添加一个简单的CSS规则来让我们的猫更清晰:
.animal i { font-size: 50px; }
保存风格。css和刷新索引。html。你应该看到一只更大的猫。
类字段
除了定义类行为的方法外,类还可以保存自己的数据。在其核心,您可以将类看作是数据加上对该数据进行操作的方法。例如,对于像猫这样的宠物,我们可能想给猫起个名字。名称是数据,方法的示例可能是允许我们设置或更改名称的函数。
类字段允许我们指定类专有的数据。字段只是变量声明:
class Cat { string name; }
类字段不同于常规变量声明,因为它们只能通过类或类实例访问。此外,我们声明了一个“name”字段,该字段是上面一个类实例的专有字段;这意味着类的每个唯一实例都将有自己唯一的名称数据。
特定实例特有的数据可能非常有用,尤其是在处理大量类似对象时。然而,我们当前将cat呈现到页面的代码实际上并没有保留实例的唯一数据!让我们观察一下;换个总水管。jspp代码如下,以便再次调用render():
import Animals; Cat cat = new Cat(); cat.render(); cat.render();
编译代码并打开索引。html。你应该看到两个猫被渲染,但是我们只有一个“猫”类的实例。这并不理想;相反,如果我们想向页面呈现两个Cat,我们希望需要两个“Cat”实例。为此,我们必须检查render()代码:
class Cat { void render() { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); $("#content").append($element); } }
你知道怎么了吗?
每次调用render()方法时,我们都会调用jQuery来创建一个新对象,然后通过jQuery的append()方法将该新对象呈现到页面上。我们需要做的是让页面元素的创建成为 类实例 。我们可以通过简单地将render()中的变量声明移动到类字段来实现。以下是我们的完整代码:
external $; module Animals { class Cat { var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); void render() { $("#content").append($element); } } }
在上面的代码中,除了将变量声明从render()移动到类本身,使其成为字段之外,我们什么也没做。现在,只有在实例化该类时,才会初始化该字段。换句话说,在我们使用“new”关键字实例化类之前,将不会执行将HTML转换为jQuery对象的jQuery函数调用。
保持代码与对同一个类实例的两个render()调用完全相同。然而,随着猫的更新。jspp,再次编译代码。开放索引。html。您应该只看到一只猫呈现到页面上。
现在,让我们尝试通过更新main来创建两个cat。jspp使用两个 类实例 :
import Animals; Cat cat1 = new Cat(); cat1.render(); Cat cat2 = new Cat(); cat2.render();
现在您应该看到两个cat,每个类实例一个:
用领域和方法给动物命名
虽然我们的第一个类字段示例涉及命名,但实际上我们从未在类中添加名称字段。然而,我们不只是给我们的猫命名,当我们在动物上方悬停时,我们还可以让它在网络浏览器中可见。正如我们在上一个示例中所展示的,像名称这样的字段对于类实例应该是唯一的——如果给了不同的名称,页面上的任何两个cat元素都不应该显示相同的名称。
在Cat中插入以下代码。jspp:
external $; module Animals { class Cat { string name; var $element = $( """ <div class="animal"> <i class="icofont icofont-animal-cat"></i> </div> """ ); void setName(string name) { this.name = name; } void render() { $("#content").append($element); $element.attr("title", name); } } }
我们添加了一个新字段:“name”,类型为“string”。我们还添加了一个新方法“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元素上时,我们将看到它的名称。
在我们能看到结果之前,我们必须把猫的名字放在主目录中。jspp。让我们这样做:
import Animals; Cat cat1 = new Cat(); cat1.setName("Kitty"); cat1.render(); Cat cat2 = new Cat(); cat2.setName("Kat"); cat2.render();
确保调用了“setName” 之前 “渲染”方法。
编译代码。同样,对于Windows、Mac和Linux用户,命令现在都是一样的:
$ js++ src/ -o build/app.jspp.js
如果程序编译成功,请打开索引。html。将你的名字悬停在每只猫的上方。你应该看看它的名字。