首页 > 编程语言 >面向-SAP-ABAP-开发者的-JavaScript-基础知识-全-

面向-SAP-ABAP-开发者的-JavaScript-基础知识-全-

时间:2024-10-05 17:14:03浏览次数:8  
标签:console 函数 示例 JavaScript 清单 ABAP var SAP log

面向 SAP ABAP 开发者的 JavaScript 基础知识(全)

原文:JavaScript Essentials for SAP ABAP Developers

协议:CC BY-NC-SA 4.0

一、JavaScript 简介

本章为 ABAP 开发者提供了 JavaScript 的介绍。我们先从学习 JavaScript 的必备知识开始。然后,我们将介绍 JavaScript 的基础知识,以及 ABAP 和 JavaScript 之间的一些差异。接下来,我们将看一个非常简单的程序和你自己创建它的必要步骤。

简单的 JavaScript 背景

JavaScript 是 ECMAScript 语言规范中标准化的高级、动态、非类型化语言。与超文本标记语言(HTML)和级联样式表(CSS)一起,JavaScript 是另一项最初推动 Web 应用架构的重要技术。所有现代 web 浏览器都支持 JavaScript (JS ),并且今天大多数网站和 web 应用都在使用它。一开始,使用 JavaScript 的典型例子包括在网页上创建交互效果和在网站上进行表单数据验证。从那以后,许多库都是用 JS 编写的,比如 jQuery。

注意

有一种常见的误解,认为 JavaScript 和 Java 是相似的。它们是不相关的,并且具有不同的语义。JavaScript 的语法源自 C 编程语言。

此外,JS 语言在服务器端编程中用作几种不同浏览器引擎的运行时引擎,如 V8 (Google Chrome)和 SpiderMonkey (Firefox)。最广为人知和使用的 JS 运行时环境之一叫做 NodeJS。

JavaScript 与 C 语言在语法上有一些相似之处,比如 switch 和 if 语句以及 while 和 do while 循环。在 JavaScript 中,类型与值链接,而不是与变量链接。例如,一个名为 myvar 的变量可以先被赋予一个字符串,然后被反弹为一个数字。

JavaScript 是一种区分大小写的语言,这意味着任何语言关键字、变量名和函数名都必须用一致的大写字母书写。例如,关键字 case 必须写成“case”,而不是“CASE”或“Case”

JavaScript 是一种多参数语言,允许命令式编程、面向对象编程和函数式编程。它允许你处理文本、数字、日期和数组。JavaScript 中还提供了正则表达式处理功能。然而,JS 不提供任何网络或图形功能。JavaScript 支持使用类进行继承的原型(与许多其他面向对象的语言不同,如 ABAP)。许多基于类的特性可以使用 JavaScript 中的原型来编程。

在 JavaScript 程序内部

本节详细介绍 JavaScript 程序的各种不同的代码元素。

JavaScript 程序由许多语句组成。每条语句都以分号(;).JavaScript 区分表达式和语句。语句可以由文字、变量和表达式组成。给定的 JS 语句可能跨越多行。此外,在一行中可以写多条语句。

注释是任何代码的重要组成部分。JavaScript 忽略了它们,但它们是程序员记录代码目的的重要工具,供以后审查。有两种类型的注释可以添加到 JavaScript 程序中。首先,您可以添加单行注释,如下所示:

var num = 1; // from here comments start

如您所见,单行注释以双斜线(//)开始。该行中所有后续代码/文本都被视为注释文本。标记单行注释的结尾不需要结尾标点;这条线的尽头就是为了这个目的。

JavaScript 还允许您指定多行注释。这些行可以包含在//之间,并且可以包含一行或多行。在多行注释中,嵌套是不可能的。试图嵌套多行注释会产生语法错误。清单 1-1 显示了一个在 JS 中不可接受的例子。

清单 1-1。错误嵌套的注释
/*  this is comment 1
/*  this is comment 2  */
*/

正如你所看到的,这个例子试图在注释 1 中嵌套注释 2,这是不允许的,并且会产生语法错误。

在 JavaScript 程序中,语句是逐行执行的(即顺序执行)。一组语句可以组合在一起形成一个块。块的开始和结束用花括号({ })表示。这些块可能包括函数中的代码(函数类似于 ABAP 中的子例程)或 if 语句或 switch 语句中的代码。

一个 JS 程序可能包含许多文字。在 JS 中使用文字来表示程序中使用的固定值(与变量相反)。这些文字的一些例子是整数和字符串文字。

在 JavaScript 中,字符串包含在一组双引号("")或一组单引号('')中,而 ABAP 字符串只包含在单引号中。其他类型的文字有数组文字、布尔文字和对象文字。

创建一个简单的 JS 程序

现在您已经对 JavaScript 有了一些基本的了解,本节将向您展示如何制作一个简单的程序,然后解释它的各个部分。

您将创建一个小程序,在弹出对话框中显示“我的第一个 JS 程序”的消息。JS 中有一个内置的函数 alert,可以让您向用户显示一条消息。这个函数可以接受文字或变量形式的数字或字符串作为输入。

这个程序的代码如清单 1-2 所示。

清单 1-2。在弹出对话框中显示文本的程序
<html>
   <body>
      <script>
             alert("First JS program by an ABAP Developer");
      </script>
    </body>
</html>

如您所见,该程序使用一个字符串文字(在双引号内)向用户显示消息。运行此示例会在弹出的对话框中显示一条消息,如图 1-1 所示。

A394309_1_En_1_Fig1_HTML.jpg

图 1-1。程序输出

快速浏览 HTML

JavaScript 代码不能单独执行。它依赖于运行时环境来包含/导入脚本(例如,HTML

HTML 是用来创建网页的语言。在网页源代码文本中,有许多标签。简单来说,标签是 HTML 文档中的代码,以符号<开始,以>结束。标签通常成对出现,一对标签指示浏览器如何处理标签对中出现的文本。

每个标签都有特殊的含义,有自己的效果。标签由浏览器读取并相应地解释。浏览器不会显示标签。然后,浏览器向查看者呈现并显示网页。

注意

HTML 不是区分大小写的语言:、、都有同样的效果。但是,您必须确保结束标记,比如,包含一个正斜杠,而不是反斜杠。写会出问题。

在这个阶段,您只需要知道 HTML 的细节,这些细节将帮助您运行将要编写的 JS 代码。HTML 文档中存在许多元素,它们被表示为标签:

  • HTML 标签和标记了 HTML 文档的开始和结束。浏览器根据 HTML 标记中包含的信息呈现页面。确保没有代码写在标志 HTML 文档结束的

  • HEAD 标签包含与文档相关的一般信息,例如页面的使用以及与其他文档和资源的链接。例如,一对标签可能包含与网页相关的 JS 文件和 CSS 代码的信息。标题中是 TITLE 标签,用于指定文档的标题。标题显示在浏览器窗口的顶部。TITLE 标签还包含关于文档的元数据。

  • 和包含关于页面主体的信息——浏览器加载页面时呈现的实际内容。这对标记中包含的一些元素是页眉和页脚。在正文中,您可以显示许多文本行、表格、表单和图形。您可能有许多标题,如等等。使用

    标签,你也可以指定一个新段落的开始位置。浏览器读取正文中的各种元素,并相应地呈现页面。

现在你已经准备好看看如何编写你的第一个 HTML 代码。图 1-2 显示了一个简单的 HTML 程序,其中没有任何 JavaScript。

A394309_1_En_1_Fig2_HTML.jpg

图 1-2。HTML 无 JavaScript 代码

图 1-2 的代码输出如图 1-3 所示。

A394309_1_En_1_Fig3_HTML.jpg

图 1-3。HTML 代码输出

如果 HTML 代码中有语法错误,浏览器仍然会产生输出。但是,您可能得不到想要的结果。例如,考虑图 1-2 中所示的相同代码,其中主体中的< /H1 >标签被错误地写成< \H1 >(即带有反斜杠)。在这种情况下,整组文本行以标题样式显示,如图 1-4 所示。

A394309_1_En_1_Fig4_HTML.jpg

图 1-4。HTML 页面的错误输出

将 JavaScript 放入 HTML 代码中

本节向您展示如何将本章前面的 JavaScript 代码添加到上一节的简单 HTML 页面中。您可以选择几种方法中的任何一种来实现这一点。最简单的方法是将整个 JS 代码写在 HTML 页面的头部或主体中。也可以将 JS 代码编写为一个单独的文件,并将文件名包含在 HTML 代码中。让我们逐一考虑这些方法。请注意,它们都在浏览器显示中产生相同的输出。

在和标签中编写 JS 代码

第一种方法是在 HEAD 元素中包含整个 JavaScript 代码。例如,您可以将您在清单 1-2 中编写的 JS 代码嵌入到上一节创建的 HTML 代码中(如图 1-2 所示)。包含 JavaScript 的 HTML 代码如清单 1-3 所示。

清单 1-3。头部带有 JS 代码的 HTML 代码
<!DOCTYPE html>
<html>
 <head>
   <title>My first Web Page</title>
    <script>
      alert("First JS program by an ABAP Developer");
    </script>
  </head>
<body>
</body>
</html>

如您所见,单行 JS 脚本是在 HEAD 标记中编写的。当浏览器到达标签之后的剩余 HTML 代码。

在和标签中编写 JS 代码

另一种方法是将 JavaScript 代码包含在 BODY 元素中,在

清单 1-4。在 HTML 主体中添加 JavaScript
<!DOCTYPE html>
<html>
 <head>
   <title>My first Web Page</title>
 </head>
<body>
<script>
      alert("First JS program by an ABAP Developer");
</script>
</body>
</html>

与前面的方法一样,当浏览器到达标记后的剩余 HTML 代码。

在单独的文件中创建 JS 代码

另一种常用的方法是将 JS 代码包含在与 HTML 代码分开的文件中,并在 HTML 代码中包含指向 JS 文件的链接。这种方法有几个优点:它使 HTML 代码和 JavaScript 代码都更容易理解和维护。清单 1-5 展示了如何在 HTML 代码中链接到一个 JS 文件。

注意

当将外部 JS 文件链接到 HTML 代码时,请确保 JS 文件的名称以正确的大小写书写。例如,不要将 Code.js 写成 code.js 或 CODE.JS。

清单 1-5。用 HTML 代码处理 JS 文件
<!DOCTYPE html>
<html>
 <head>
   <title>My first Web Page</title>
    <script src="Code.js">   // JS file name
    </script>
  </head>
<body>
</body>
</html>

这个例子假设 JavaScript 代码包含在一个单独的文件中,在 HTML 代码所在的目录中。如您所见,包含 JS 代码的文件名(在本例中是 Code.js)是在 HEAD 元素中指定的。您必须确保以正确的大小写书写文件名。

同样,一旦到达标签之后的剩余 HTML 代码。

JavaScript 中的变量声明

变量声明是任何编程语言的重要组成部分。声明变量使您能够为程序中使用的值指定符号名。JavaScript 变量名必须以下列之一开头:

  • 一个字母(包括大写字符 AZ 和小写字符 az

  • 下划线(_)

  • 美元符号($)

名称不能以数字(0-9)开头,但后面的字符可以是数字。允许的变量名包括 Nu_hits、Mytemp13 和 _myname。

JavaScript 中定义的变量要么是具有全局执行上下文的全局变量,要么是特定于特定函数的局部变量(我们将在本书的后面部分讨论这一点)。局部变量只在定义它的函数内可见/可访问,在函数外不可见/可访问。全局变量对整个 JS 程序是可见的/可访问的。

JavaScript 中的变量是使用 var 关键字声明的。下面是语法:

var num; 

也可以在同一行代码中声明变量并初始化它:

var num = 1;

您也可以在一行中链接两个变量声明(使用逗号将它们链接在一起):

var num1, num2;

也可以在一行代码中初始化一个或两个变量:

var num1, num2 = 1;

您不需要指定变量的类型。声明从分配给它的值中获取类型。

注意

与 ABAP 不同,JavaScript 允许你声明变量,然后改变它们的类型。

您也可以使用相同的 var 语句声明一个变量并用一个值初始化它,然后将该变量及其值赋给另一个变量:

var num1 = 10;
var num2 = num1;

如您所见,变量 num1 是用值 10 声明和初始化的。在第二条语句之后,num2 变量被声明为一个数字,并被赋值为 10。在语句之后,两个变量的值都是 10。

也可以在以后更改变量的类型。例如,如果变量 num1 是一个数字,以后可以将其更改为字符串,如下例所示:

var num1 = 10;
num1 = "my string";

在 JavaScript 中,你也可以在变量被使用后声明它。换句话说,你甚至可以在声明变量之前使用它。考虑下面这段简短的代码:

num1 =  10;
var num1; 

在这种情况下,我们有一个名为 num1 的变量,其值为 10。代码的后面是使用 var 关键字定义变量。JS 的这个特点被称为变吊。当加载和执行 JS 程序时,首先处理所有声明变量的 var 语句(即,在程序代码的其余部分之前)。

如前所述,JavaScript 是一种区分大小写的语言。这意味着你可以用相同的字母创建不同大小写的变量。例如,考虑下面的例子:

var message = "Second JS Program - Message 1";
var MESSAGE = "Second JS Program - Message 2";

这段代码定义了两个独立的变量 message 和 MESSAGE,每个变量都被赋予了不同的字符串值。不鼓励这种做法,以避免混淆。

使用 Eclipse

创建 JavaScript 程序没有单一的编辑器。您有多种选择,例如

  • 笔记本

  • SAP Web IDE

  • 便笺本

  • 记事本++

在这一部分和整本书中,我将演示如何使用我选择的编辑器 Eclipse IDE 创建 JavaScript 程序。向您展示整个 Eclipse 安装过程超出了本章的范围。你应该可以通过 www.eclipse.org 的在线说明很容易地安装它,你也可以在那里下载 Eclipse。

成功安装 Eclipse 后,双击桌面上的快捷方式,如图 1-5 所示。

A394309_1_En_1_Fig5_HTML.jpg

图 1-5。Eclipse 快捷方式
注意

所有的例子和截图都是在 Windows 中测试的。

或者,如果您使用的是 Windows,您可以使用程序菜单打开 Eclipse。这两个选项都将您带到 Eclipse 编辑器的开始屏幕,如图 1-6 所示。

A394309_1_En_1_Fig6_HTML.jpg

图 1-6。Eclipse 编辑器

现在您需要创建一个 Eclipse JavaScript 项目。选择菜单路径文件➤新➤项目。出现新建项目对话框,如图 1-7 所示。展开 JavaScript 文件夹,选择 JavaScript 项目节点,然后单击 Next 按钮。

A394309_1_En_1_Fig7_HTML.jpg

图 1-7。创建 JavaScript 项目

在出现的向导屏幕上,输入项目的名称(在本例中,首先输入)。不要更改屏幕上的任何其他值,并单击 Finish 按钮。现在屏幕出现如图 1-8 所示。

**A394309_1_En_1_Fig8_HTML.jpg

图 1-8。项目“第一”

在左侧面板中,您可以看到名为 First 的项目最初没有 HTML 或 JavaScript 文件。现在,您将把 JavaScript 和 HTML 文件添加到这个项目中。要添加 JavaScript 代码,只需右键单击第一个项目节点,然后选择“新建➤ JavaScript 源文件”。在出现的对话框中,输入文件的名称。对于这个例子,输入 Code.js 。然后,单击“完成”按钮。

左窗格将出现如图 1-9 所示。

A394309_1_En_1_Fig9_HTML.jpg

图 1-9。添加了 Code.js 节点

如您所见,第一个项目文件夹中添加了一个新的 Code.js 节点。要向 Code.js 文件添加代码,只需双击该节点。右窗格变化如图 1-10 所示。

A394309_1_En_1_Fig10_HTML.jpg

图 1-10。JavaScript 编辑器

只需在程序中添加如图 1-10 所示的代码,并使用组合键 CTRL+S 保存代码,如您所见,本例使用了两个名称相似但大小写不同的变量(message 和 MESSAGE)。它还使用两个警告语句向用户输出值。

接下来,您需要向项目中添加一个 HTML 文件。首先右键单击文件夹,然后选择“新建➤文件”。在出现的对话框中,输入带有 html 扩展名的文件名(在本例中为First.html)。在右侧面板的 html 编辑器中输入 HTML 的代码(参见图 1-11 )。

A394309_1_En_1_Fig11_HTML.jpg

图 1-11。HTML 编辑器

正如您所看到的,这个例子使用了

接下来,保存您的项目。现在您可以在 Eclipse 中测试您的代码了。为此,右键单击 HTML 文件节点,然后选择“运行➤浏览器”。

您将在右侧面板中看到输出。因为你在程序中写了两条 alert 语句,第一条 alert 语句的输出显示在一个对话框中,如图 1-12 所示。

A394309_1_En_1_Fig12_HTML.jpg

图 1-12。显示警告的 JavaScript 编辑器

单击第一个对话框的确定按钮将显示第二个对话框。

您已经在 Eclipse 中成功地创建了一个 JavaScript 程序,为后续章节的构建奠定了基础。

摘要

这本书的第一章介绍了 JavaScript 的基础知识。您看到了如何在程序中定义和使用变量,以及如何创建一个简单的 JS 程序。此外,您还了解了用于创建 JavaScript 程序和 HTML 代码的 Eclipse IDE。在下一章中,您将更详细地探索这种语言,包括 JavaScript 语言支持的数据类型。**

二、JavaScript 更进一步

在第一章中学习了 JavaScript 的基础知识和运行一个 JavaScript (JS)程序的先决条件之后,你就可以开始学习 JS 语言的细节了。本章首先给你一个窗口对象的概述。接下来,它详细描述了 JavaScript 提供的数据类型。然后,演示程序将向您展示如何在对话框中向用户显示数据,如何在 web 浏览器的控制台中调试您的 web 页面,以及如何通过对话框接受用户的输入。本章的最后一节列出了 JS 语言的保留字。

窗口对象

JavaScript 中的一个重要概念是窗口对象。window 对象代表浏览器中打开的窗口。本节描述该对象及其提供的属性和方法。

在 JS 程序中,在任何函数之外声明的所有变量本质上都是全局的。它们在网页的整个执行过程中保持活动状态。全局变量是这个对象的属性。该组全局变量可通过全局窗口对象来访问。窗口对象的任何组件都可以通过使用点符号(.).

为了更好地理解 Window 对象,考虑以下 JS 程序的摘录:

var num1 = 10;
window.num1 = 20 ;
alert (num1);

该语法声明了一个变量 num1,并给它赋值 10。然后,它使用 window 对象来访问 num1,并给它赋值 20。短 JS 程序输出如图 2-1 所示的值。

A394309_1_En_2_Fig1_HTML.jpg

图 2-1。程序输出

如您所见,显示的是值 20,而不是 10。这是因为变量 num1 驻留在通过窗口对象访问的全局容器中。当您赋值 20 时,它引用同一个变量 num1。

Window 对象包含许多属性和方法,所有主流浏览器都支持它。表 2-1 中列出并简要描述了与之相关的一些重要属性。

表 2-1。窗口对象的重要属性
|

财产

|

目的

|
| --- | --- |
| 状态 | 设置或返回浏览器底部的状态栏文本 |
| 名字 | 设置或返回窗口的名称 |
| 全屏 | 指示窗口的全屏显示 |
| 内部高度 | 设置窗口内容区域的高度,包括水平滚动条 |
| 内宽 | 设置窗口内容区域的宽度 |
| 长度 | 设置窗口中的帧数 |

此外,Window 对象还有很多有用的方法。表 2-2 中列出并简要描述了一些重要的方法。

表 2-2。窗口对象的重要方法
|

方法

|

目的

|
| --- | --- |
| 警报() | 向用户显示带有消息文本和确定按钮的警告框 |
| 提示() | 生成供用户输入的对话框 |
| 打印() | 写入相关窗口的内容 |
| 打开() | 在浏览器中创建新窗口 |
| 关闭() | 关闭窗口 |
| 确认() | 显示带有“确定”和“取消”按钮的对话框以及相应的消息 |
| createPopup() | 创建弹出窗口(此方法在 Internet Explorer 中有效) |

JS 程序的所有部分都可以调用这些方法。调用这些方法时,可以使用窗口对象,也可以不使用窗口对象调用这些方法。考虑以下示例:

Window.alert("Hello"); //  incorrect, as Window must be written in lowercase i.e. window
window.alert(text);    //  correct
alert("Hello");        // correct

前面两种说法效果相同。没有必要将调用与窗口对象一起使用。

注意

当调用窗口对象时,总是使用小写字母。

JavaScript 中的数据类型

第章 1 简单介绍了 JS 中可用的数据类型。本节将更深入地探讨 JavaScript 支持的各种数据类型。在 JavaScript 中,变量被赋予在给定实例中分配的类型。

总的来说,JavaScript 中存在六种数据类型,如表 2-3 中所总结的。下面的小节更详细地描述了它们,并展示了如何声明它们。

表 2-3。数据类型及其用途
|

类型名称

|

目的

|
| --- | --- |
| 线 | 一组字符 |
| 数字 | 整数,负数或正数,或各种小数 |
| 不明确的 | 具有此类型的变量已定义,但没有值 |
| 空 | 对没有值的变量的有意或明确的说明 |
| 目标 | 一组未排序的属性和属性值 |
| 布尔代数学体系的 | 包含真或假 |

线

字符串是各种长度的字符序列。典型的例子包括“约翰 123”和“约翰是个好人”。字符串必须用引号括起来。通常,使用双引号。但是,也可以使用单引号。考虑以下代码摘录:

var person = "John James";       // double quotes
var areaName = 'Burj Khalifa';   // Using single quotes

也可以在用双引号括起来的字符串中使用单引号。考虑以下示例:

var text = "It's a rainy day";  // correct

或者,您可以使用以下可接受的形式:

var text = "My profession is 'Computer programmer'";  //correct

同样,您可以在单引号中的 sting 中使用双引号:

var text = 'My Profession is "Computer programmer" '; // correct

但是,以下示例是不可接受的,并且会产生语法错误:

var text = 'My profession is 'Computer programmer'';  // wrong
var text = "My profession is "Computer programmer'"'; // wrong

让事情变得稍微复杂一点的是,这两种不可接受的形式可能会稍微调整一下,以避免语法错误。文本中的单引号必须以反斜杠开头。现在考虑同一个例子:

var text = 'My Profession is \'Computer programmer\'  ' ; // correct

语句执行后,变量文本包含我的职业是‘计算机程序员’。

同样,以下语句也是可以接受的:

var text = "My Profession is \"Computer programmer\"  " ; // correct

执行后,变量文本包含我的职业是“计算机程序员”。

字符串定义和赋值可以在一行或一组行中。在多行中使用字符串定义时,可以使用转义换行符(\n),如下所示:

var text = "My Profession is \nComputer programmer" ;
alert(text);

执行前面几行代码后,变量文本的内容显示在如图 2-2 所示的窗口中。

A394309_1_En_2_Fig2_HTML.jpg

图 2-2。两行显示的字符串

如图所示,文本由两行组成。这是通过在字符串规范中使用\n 来实现的。

另一个可以在字符串上下文中使用的运算符是+。考虑下面一行代码:

var string1 = 'ABAP' + 'er' ; // string1 contains ABAPer

添加+运算符会导致两组字符的连接。变量 string1 将包含“ABAPer”。现在考虑下面的例子:

var string1  = 1 + '7'; //

在这种情况下,执行语句后,string1 变量的值为“17”。它导致数字 1(也被视为字符串)与字符串“7”的串联,并且 string1 中的结果也是一个字符串。

考虑另一个例子:

var string1  = 'A' + 1 + 7;  //  string1 will contain A17

在这种情况下,当执行该语句时,变量 string1 将包含值“A17”而不是“A8”。

相反,考虑下面的例子:

var string1  = 1 + 7 + 'A' ;  

执行此语句后,string1 中的结果值是“8A”而不是“17A”。原因是 JavaScript 按顺序将 1 和 7 视为数字并执行加法,直到遇到字母 A。从这一点开始,到目前为止计算出的值(8)与 A 连接并存储在变量 string1 中。变量 string1 的类型是 string。

数字

为了表示数值,JavaScript 只有一种数据类型:number。这些数字可能有也可能没有小数点。此外,它们可能包含也可能不包含一元运算符。为了澄清数字在 JS 中的用法,让我们考虑几个例子。

以下代码行表示一个包含值 26 的整数:

var num1 = 26;

现在考虑另一个例子:

var num2 = -26;

变量 num2 被赋值为负 26。

在 JavaScript 中定义变量时,不需要指定小数位数。分配变量时,必须提供相应的值。现在让我们考虑几个十进制数的例子。以下是正十进制值的一些示例:

var num1 = 0.6888 ;
var num2 = 122.688;
var num3 = 10.0;

你也可以有一个带负号和小数位的数字:

var num4 = -2.3;

您也可以为数字变量指定一个指数值。以下是一些例子:

var num5 = 28.5e-3 ; //which is equal to .0285
var num6 = 28.5e3  ; //which is equal to 28500  

这将在变量 num1 中存储值 2.78900 以及必要的小数位。

可以执行添加操作:

var num1   = 2.78900 + 1 ;

当执行加法时,结果值将是 3.789。

在 JS 内部,有两个特殊的数字:正无穷大(无穷大)和负无穷大(-无穷大)。程序中的算术溢出会导致正无穷大。另一方面,如果试图存储(在一个数字变量中)一个小于允许最小值的值,就会出现负无穷大。

注意

一个数字变量可能包含两个特殊的值:无穷大和-无穷大。

请考虑下面的示例,它演示了数字类型也用于存储十六进制和八进制值。十六进制值从 0x 开始:

var Hexval1 = -0xFFDD;
var Hexval2 =  0xFFDD;

八进制值以零开始:

var Octval = 0628;

不明确的

如果已经声明了一个变量,但没有给它赋值,则该变量的类型为 undefined。考虑以下示例:

var mytype ;

正如您所看到的,这个例子声明了变量 mytype,但是没有给它赋值。变量 mytype 的类型未定义。

var mytype ;  // mytype has undefined type

也可以将变量显式设置为 undefined:

var mytype =  10;    // mytype has type number
mytype = undefined;  // now mytype has type undefined

JavaScript 中使用 null 数据类型来显式指定变量没有值。您可以简单地将 null 赋给一个变量,如下例所示:

var mytype = 1 ;
var mytype = null; // mytype has type null
注意

将 null 或 undefined 赋给变量时,不要在 null 或 undefined 两边加上单引号或双引号。否则,它们将被视为字符串。

目标

JavaScript 中的 object 数据类型表示一组无序的属性和值。在程序中定义对象的语法如下:

var  myobj = { property1 :  val1 ,  property2 :val2 ...  property : valn };

对象定义可以写在一行或多行上。属性和相应的值必须用冒号分隔,而属性-值对用逗号分隔。在程序中,对象也是通过 var 关键字定义的变量。然而,对象是由许多属性和值组成的。

考虑这个例子:

var employee1 = { pernr :  '1', empName : "John Wright" ,  gender : 'M', country : "USA" } ;

此示例定义了一个名为 employee1 的对象,其属性为 empName、gender 和 country,并为各个属性赋值。

相同的定义和赋值可以在多行中完成:

var employee1 = {  pernr :  '1',
                   empName : "John Wright" ,  
                   gender : 'M',
                   country : "USA" } ;

定义对象时,请确保仅使用大括号{ }将属性和值对括起来。用括号将它们括起来会产生语法错误,这是不允许的。

要处理各种属性,请使用点运算符:

alert ( employee1.pernr) ;

前面的语句将显示一个值为 1 的对话框。

还可以更改给定对象的特定属性值:

employee1.pernr = 2 ;

一旦完成,对于 employee1 对象,pernr 的值将为 2。

您可以将一个给定对象分配给另一个对象,如下所示:

var employee1 = { pernr :  '1', empName : "John Wright" ,  gender : 'M', country : "USA" } ;
var employee2 = employee1;
employee2.pernr = '2';
employee2.empName = 'James Dolman' ;

alert ( employee2.pernr + " " + employee2.empName + " " + employee2.gender + " " + employee2.country ) ;

如您所见,该示例首先创建一个名为 employee1 的对象,并为员工 John Wright 分配适当的属性值,员工编号为 1。接下来,将对象 employee1 分配给新声明的对象 employee2。对象 employee2 的属性 pernr 和 empName 被更改,并使用 alert 函数在对话框中输出。程序的输出如图 2-3 所示。

A394309_1_En_2_Fig3_HTML.jpg

图 2-3。程序输出

指定对象的属性时,可以指定 undefined 或 null 作为属性值。指定 null 的示例如下所示:

var employee1 = { pernr : null, empName : null ,  gender : 'M', country : "USA" } ;
employee1.pernr = '2' ;
employee1.empName = 'John Reed' ;

除了点符号之外,还有另一种方法来处理对象的属性。这显示在以下代码行中:

employee1["pernr"] = '2' ;  correct

这将把值“2”赋给 employee1 对象的属性 pernr。如您所见,属性名用双引号和方括号括起来。也可以用单引号将属性名括起来。考虑以下具有相同效果的语句:

employee1['pernr']  = '2';   //  correct

但是,您必须确保在单引号或双引号中只使用方括号,如示例所示。使用圆括号或花括号会产生语法错误:

employee1('pernr') = '2' ;   //  Wrong

此外,省略引号(单引号或双引号),即使与方括号一起使用,也是有问题的,如下所示:

employee1[ pernr ] = '2' ;   //  Wrong

对象中的对象

到目前为止,您已经看到了只包含一组属性的对象的例子。现在您将看到如何定义包含一个或多个其他对象的对象。您可以通过稍微修改前面的 employee1 示例来实现这一点。修改后的示例没有使用基于字符串的属性名,而是引入了一个新的属性 fullname,它基于一个具有属性 lastname 和 firstname 的对象。这方面的代码如下:

var employee1 = {  pernr :  '1',
                fullname : { lastname : "John" , firstname : "Wright" } ,  
                gender : 'M',
                country : "USA" } ;

这里,与最初的示例一样,定义了一个具有许多属性的对象 employee1。但是,employee1 现在有一个名为 fullname 的属性,它本身是一个包含属性 lastname 和 firstname 的对象。请注意 employee1 和 fullname 对象的花括号用法。在子对象中,冒号和逗号的使用方式与它们在主对象规范中的使用方式相同。

考虑下面几节中描述的例子。

注意

JavaScript 中存在一种称为数组的特殊对象。数组是一组有序的值,写在方括号内;如[1,2,7,10]或['我的','她']。数组将在第五章和后续章节中详细讨论。

布尔代数学体系的

顾名思义,基于布尔数据类型的变量的值可以是 true 或 false。请考虑以下几点:

var  bool1 =  true;  // correct
var  bool2 = false ; // correct

这些示例定义了两个布尔变量 bool1 和 bool2,并分别为它们赋值 true 和 false。重要的是,赋值不能用单引号或双引号写,必须用小写字母写。

注意

当您将 true 和 false 赋给布尔变量时,请确保不要将它们写在单引号或双引号中。否则,它们将被视为字符串。还要确保全部使用小写字母。

考虑这些例子:

var  bool1 =  "true";  // wrongly defined as string - not boolean
var  bool2 = "false" ; // wrongly defined as string - not boolean  

这里,bool1 和 bool2 都是字符串,而不是布尔值。

布尔变量用于条件求值,并可用于存储条件求值的结果,如 if 和 while 语句。(这些陈述将在本书的后半部分详细讨论)。考虑下面一行:

var boolean1 =  ( 10 > 1 ) ;

执行脚本后,变量 boolean1 包含值 true。接下来,考虑这个例子:

var boolean2 =  ( 0 > 1 ) ;

在这种情况下,boolean2 变量包含值 false。

运算符的类型

JavaScript 中一个重要的操作符是 typeof 。typeof 运算符返回一个字符串,该字符串表示所讨论的操作数的类型。typeof 运算符的语法如下所示:

typeof (variable) ;
typeof variable ;

变量或操作数可以属于本章讨论的任何类型。如果使用 typeof 运算符计算单个语句中的单个操作数,可以省略变量名两边的括号。您还可以在 alert 方法或 console.log 方法中使用 typeof 运算符(将在下一节中讨论)。

以下示例显示了如何使用 typeof 运算符:

var text = 'My Profession is "Computer programming" '.
alert (typeof(text));     //    string  displayed in dialog box

在此示例中,typeof 运算符返回一个字符串,该字符串显示在对话框中。

考虑以下代码,其中运算符正确地返回了对象类型:

var employee1 = {  pernr :  '1',
fullname : { lastname : "John" , firstname : "Wright" } ,  
             gender : 'M',
             country : "USA" } ;
alert (typeof(employee1) ) ; //  object displayed in dialog box

在下面的代码中,变量 boolean1 属于布尔数据类型。因此,typeof 运算符返回布尔值。

var boolean1 =  ( 10 > 1 ) ;
alert (typeof(boolean1)) ;   //  boolean displayed in dialog box

如前所述,当变量被声明但没有赋值时,变量的类型是未定义的。相同的未定义类型由 typeof 运算符确定:

var mytype ;  // mytype has undefined type
alert (typeof(mytype)) ;   // undefined displayed in dialog box

typeof 运算符也适用于数字,并给出正确的类型(即数字):

mytype =  10;  // mytype has type number
alert (typeof(mytype)) ;   // number displayed in dialog box

最后,此示例显示了当涉及 null 时 typeof 运算符的行为:

mytype = 1 ;
mytype = null; // mytype has type null
alert(typeof( mytype)) ;  // but  object displayed in dialog box ----wrongly displayed

在空值的情况下,typeof 运算符错误地将类型名返回为 object。开发人员需要小心谨慎,并编写适当的措施来处理这种情况。

警告

typeof 运算符在所有情况下都返回正确的 JS 类型,但类型 null 除外。在这种情况下,它错误地返回“object”。

方法控制台. log

到目前为止,在本章中你已经看到了 JS 中各种可用的数据类型以及一些例子,包括如何使用 alert 方法在对话框中显示信息。但是,出于测试和调试的目的,您可能需要在程序执行过程中的不同时刻显示某些变量的值。

注意

不建议在实际环境中使用 console.log 方法。但是,在开发 JS 程序时,必须使用它进行测试。

在执行程序时,可以使用 console.log 方法显示变量的测试值。虽然颜色和风格化选项是可能的,但这里我们将只讨论该方法的基本工作。这种方法的语法如下:

console.log( obj1, obj2 ....objn );

console.log 方法可以接受一个或多个数字、字符串、布尔值或对象作为输入。还可以使用 console.log 方法显示对象的一个或多个属性。还可以将 console.log 与 typeof 运算符结合使用。对于包含更多对象的对象,您可以深入查看该对象的更多详细信息。

注意

当传递给 console.log 方法的值涉及要执行的操作(如加法或串联)时,首先计算结果,然后输出结果。

以下示例显示了实际使用的 console.log 方法:

<!DOCTYPE html>
<html>
<body>
<h1>Console Log Demo </h1>
<script>
  console.log(10 + 5);
</script>
</body>
</html>

Console 对象允许您访问浏览器的调试控制台。console.log 方法的输出既不与浏览器中的其余网页内容一起显示,也不在加载网页时的弹出框中显示。相反,它显示在浏览器调试器的控制台选项卡中。打开控制台显示器的步骤如下:

  1. 在浏览器中打开包含 HTML 和 JavaScript 代码的网页。(在这个例子中,我使用的是谷歌浏览器。)

  2. 按 Ctrl+Shift+I。这将在网页输出右侧的单独窗格中打开调试器,如图 2-4 所示。

    A394309_1_En_2_Fig4_HTML.jpg

    图 2-4。调试器控制台选项卡
  3. 单击控制台选项卡。现在您将看到使用 console.log 方法显示的值(在图 2-4 中,15 显示为相加的结果)。

注意

确保在 JavaScript 代码中使用小写字母编写 console.log。将其写入 Console.log 不会产生预期的结果。

考虑清单 2-1 中的例子。

清单 2-1。显示对象员工 1
<script>
var employee1 = {  pernr :  '1',
                   empName : "John Wright" ,  
                   gender : 'M',
                   country : "USA" } ;

console.log(employee1);
</script>

这里,employee1 对象作为参数传递给 console.log 方法。控制台中的输出如图 2-5 所示。

A394309_1_En_2_Fig5_HTML.jpg

图 2-5。控制台中显示的员工 1 对象

如您所见,该对象与相关属性和值一起显示在一行中。

现在考虑一个示例,其中对象 employee1 包括属性 fullname(这是另一个对象):

var employee1 = {  pernr :  '1',
                  fullname : { lastname : "John" , firstname : "Wright" } ,  
                  gender : 'M'',
                  country : "USA" } ;
console.log (employee1) ;

对于这样的嵌套对象,控制台输出如图 2-6 所示。

A394309_1_En_2_Fig6_HTML.jpg

图 2-6。控制台中显示的员工 1 对象

在这种情况下,不会显示 fullname 属性的值。相反,只为它显示对象。您可以展开对象节点来查看雇员 1 的全部详细信息,如图 2-7 所示。

A394309_1_En_2_Fig7_HTML.jpg

图 2-7。展开的对象员工 1

如你所见,在 Chrome 控制台的详细视图中,属性是按字母顺序排列的。

接受用户的输入

到目前为止,您已经看到了如何在对话框中向用户输出数据,以及如何在 web 浏览器控制台中调试您的网页。现在,您将看到如何从查看嵌入了 JavaScript 代码的网页的用户那里获取输入。

Window 对象的 prompt 方法用于此目的,如以下语法所示:

window.prompt ( text , optional default text ) ;
prompt ( text , optional default text ) ;

prompt 方法的调用将显示给用户的文本以及可选的默认值作为输入。网页上将显示一个对话框。这是一个模态对话框,意味着它不允许用户在浏览器中执行任何其他活动,直到对话框关闭。该对话框显示有两个按钮:“确定”和“取消”。

您可以将用户输入的文本赋给程序中声明的变量。无论使用什么类型的变量,当用户在对话框的输入字段中输入一个值并单击 OK 按钮后,返回的变量的类型将变为 string。

为了更好地理解,请考虑以下示例:

var value  = 0;
value = prompt("Enter a value", "10") ;
alert('You entered ' + value + ' which has type '  + typeof(value)  );

此示例指定一个数字变量值,然后调用 window 对象的 prompt 方法,并将输入的值赋给该变量。在方法调用中指定了默认文本 10。然后,该示例使用 alert 方法在另一个对话框中显示输入的值及其类型。该代码生成的输入对话框如图 2-8 所示。

A394309_1_En_2_Fig8_HTML.jpg

图 2-8。输入对话框

当用户输入一个值,如 10,点击确定,显示如图 2-9 所示的信息。

A394309_1_En_2_Fig9_HTML.jpg

图 2-9。显示的消息

如您所见,变量值被赋值为 10,输入的值的类型被解释为字符串。

另一方面,如果用户单击 Cancel 按钮,变量值将被赋值为 null。

JavaScript 中常用的关键字

作为本章的总结,表 2-4 列出了 JavaScript 语言中的一些关键字(保留字)。请注意,不允许定义与这些关键字同名的变量,这就是它们被称为保留变量的原因。

表 2-4。保留字
|

布尔代数学体系的

|

破裂

|

情况

|
| --- | --- | --- |
| 捕捉 | 班级 | 继续 |
| 系统默认值 | 做 | 其他 |
| 错误的 | 最后的 | 为 |
| 功能 | 如果 | 在 |
| 实例 | (同 Internationalorganizations)国际组织 | 新的 |
| 空 | 私人的 | 保护 |
| 公众的 | 返回 | 短的 |
| 静电 | 极好的 | 转换 |
| 这 | 扔 | 真实的 |
| 尝试 | 类型 | 定义变量 |
| 正在… | 随着 |   |

摘要

在本章中,您已经了解了 JavaScript 提供的窗口对象和数据类型。接下来,您看到了如何在对话框中向用户显示数据,如何在浏览器的控制台中调试 web 页面,以及如何通过对话框接受用户的输入。本章末尾列出了 JS 语言的保留字。

第三章介绍了 JavaScript 的更多细节。您将看到 JS 语言中的各种控制结构,以及如何使用它们来满足需求。

三、JavaScript 中的运算符

本章详细解释了 JavaScript 操作符。它从算术运算符开始,然后着眼于比较运算符和逻辑运算符,这些运算符用于在 JS 程序中制定条件检查。本章的最后一节介绍了赋值运算符和按位运算符。

算术运算符

算术运算符将文字或变量形式的值作为操作数,并返回单个值。JavaScript 支持的标准算术运算符在表 3-1 中列出。在接下来的小节中,将依次介绍每种方法。

表 3-1。算术运算符
|

操作员描述

|

操作员

|
| --- | --- |
| 添加 | + |
| 减法 | - |
| 增加 | * |
| 分开 | / |
| 余数(模或模数) | % |
| 指数运算 | ** |
| 增量 | ++ |
| 减量 | - |
| 一元否定 | - |

加法算子

加法运算符(+)产生数字操作数的加法(和)。对于字符串,加法运算会导致字符串串联。其语法如下所示:

A + B

以下是加法运算符的几个应用示例:

2 + 4                 //    6     addition performed
10 + "text"           //   10text concatenation
"text" +  "string"    //   "textstring"
2 + true              //    results  in value 3
1 + false             //    1

减法运算符

减法运算符(-)对两个操作数执行算术减法。语法是

x - y

对于数值操作数,返回 x 和 y 之间的差值。如果是字符串,则返回值 NaN(不是数字)。以下是减法运算符的一些示例:

10 - 6  // 4
6 - 10 // -4
"text" - 2 // NaN

乘法运算符

乘法运算符(*)确定所提供的操作数的乘积。语法是

A * B

乘法运算符的示例包括:

52 * 2 // results in 104
-22 * 2 // -44
Infinity * Infinity // Infinity
"abc" * 3 // NaN

除法算符

除法运算符(/)得出所提供的操作数的商。语法是

A / B

这里,左操作数(A)是被除数,右操作数(B)是除数。该运算符的一些示例包括

1 / 2      // returns 0.5 in JavaScript
3 / 0      // returns Infinity in JavaScript
3.0 / -0.0 // returns -Infinity in JavaScript

余数运算符

余数(或模)运算符(%)用于确定第一个操作数除以第二个操作数时的余数(余数)。余数总是有被除数的符号。语法是

 A % B

reminder 操作符的数学不太简单,所以这里提供了几个使用它的例子:

            result = ( 13 %  4 );  //    1
            result = ( -1 %  3 );  //   -1
            result = (  1 %  -3 ); //    1
            result = ( 1 % 3  );   //    1
            result = ( 2 % 6  );   //    2
            result = ( -6 % 2  );  //   -0
            result = ( 6.5 % 2) ;  //    0.5

指数运算符

取幂运算符(**)用于对第一个操作数进行第二次幂运算。语法是

A ** B

以下是取幂运算符的一些示例:

2 ** 4 // 16
4 ** 4 // 256
10 ** -2 // 0.01

增量运算符

递增运算符(++)将相关操作数的值加 1。增量运算符可以有两种形式,后缀或前缀。

后缀形式的语法是

A++

在这种形式中,变量 A 首先被返回,然后递增。

前缀形式的语法是

++A

在前缀形式中,变量 A 在返回之前首先递增。

以下是增量运算符两种形式的示例:

// Postfix
var A = 6;
B = A++; // after this, B = 6, A = 7

// Prefix
var A = 6;
B = ++A; // after this, A = 6, B = 6

减量运算符

减量运算符(-)将其操作数值减 1(即从值中减去 1)。像递增运算符一样,递减运算符可以有两种形式:后缀或前缀。

后缀形式的语法是

A--

在后缀形式中,首先返回变量 A,然后递减。

前缀形式的语法是

--A

在前缀形式中,变量 A 在返回之前首先递减。

以下是减量运算符两种形式的示例:

// Postfix
var A = 6;
var B = A--; // B = 6, A = 5

// Prefix
var A = 6;
var B = --A; // A = 5, B = 5

一元否定运算符

一元求反运算符(-)位于所讨论的操作数之前,当在表达式中使用时,对其值求反。考虑以下示例:

// unary negation
var A = 6;
B = -A; // B = -6         A = 6

在这个例子中,在语句执行之后,变量 B 包含值-6,而 A 的值仍然是 6。

比较运算符

JavaScript 支持各种比较运算符,所有这些都将在下面的小节中解释。

大于运算符

大于(>)运算符检查左操作数的值是否大于右操作数的值。如果是,条件返回 true。否则,它返回 false。语法是

A > B

小于运算符

顾名思义,小于运算符(

A < B

大于或等于运算符

当左边操作数的值大于或等于右边操作数的值时,使用大于或等于运算符(> =)的条件为真。否则就是假的。语法是

A >= B
注意

字符串根据字典顺序进行比较。

小于或等于运算符

当左边操作数的值大于或等于右边操作数的值时,使用小于或等于运算符(< =)的条件为真。否则就是假的。语法是

A <= B

清单 3-1 展示了如何使用到目前为止讨论过的 JS 比较操作符。

清单 3-1。运算符用法示例 1
<html>
   <body>

      <script >

            var a = 20;
            var b = 30;
            var result;

            console.log("(a < b) returned ");
            result = (a < b);
            console.log(result);

            console.log("(a > b) returned  ");
            result = (a > b);
            console.log(result);

            console.log ("(a >= b) returned ");
            result = (a >= b);
            console.log (result);

            console.log ("(a <= b) returned ");
            result = (a <= b);
            console.log (result);

      </script>
    </body>
</html>

执行上述程序时,浏览器控制台的输出如图 3-1 所示。

A394309_1_En_3_Fig1_HTML.jpg

图 3-1。程序输出

变量 a 和 b 分别被赋值为 20 和 30。条件的输出在变量 result 中返回。

等式和不等式运算符

本节讨论与测试相等和不相等相关的四个可用的比较运算符。它还提供了代码示例来帮助您更好地理解它们的用法。

注意

JavaScript 支持严格比较和类型转换比较。

等式运算符

如果涉及的两个操作数相等,相等运算符(==)将返回 true。在比较之前,如果两个操作数不属于同一类型,运算符将应用操作数转换。

 6   ==  6          // true
 "6"  ==  6         // true
 0   == false       // true
 0   == null        // false
 null  == undefined // true
 true ==  1         // true

不等式算子

不等式运算符(!=)如果涉及的两个操作数不相等,则返回 true。在比较之前,如果两个操作数不属于同一类型,运算符将应用操作数转换。

 6 !=   6     //  false
 6 !=  "6"    // false
 0 !=  false  // false

严格相等(恒等)运算符

如果所讨论的两个操作数在没有任何类型转换的情况下结构相等,则严格相等运算符(===)返回 true。语法是

A === B

当使用该运算符比较两个字符串时,只有当它们具有相同的字符序列和相同的长度时,才返回 true 值。

对于两个数字的比较,当它们具有相同的数值时===运算符成功。如果两个布尔值都为真或都为假,则两个布尔值严格相等。

 8 === 8   // true
 8 === '8' // false
 'Abc'  === 'Abc'  // true

非同一性/严格不等式算子

非标识运算符(!==)在下列任一情况下返回 true:

  • 这两个操作数不相等。

  • 这两个操作数不属于同一类型。

非标识运算符的语法是

A !== B

考虑以下非标识运算符的示例:

 6 !== '6' // true
 6 !== 3   // true

逻辑运算符

像许多其他编程语言一样,JavaScript 支持几种逻辑运算符。逻辑运算符用在表达式中来表示条件。在评估之后,它们返回 true 或 false 值。但是,当与非布尔值一起使用时,它们可能会返回非布尔值。表 3-2 显示了 JS 中支持的三种逻辑运算符。

表 3-2。逻辑运算符
|

操作员

|

例子

|

影响

|
| --- | --- | --- |
| ( & &) | ex1 和 ex2 | 与布尔值一起使用时,如果操作数 ex1 和 ex2 都为真,则&返回 true。 |
| (||) | 例 1 ||例 2 | 与布尔值一起使用时,如果至少有一个操作数为 true,则||返回 true。如果 ex1 和 ex2 都为 false,||运算符将返回 false。 |
| 不是(!) | !ex1 | 当所讨论的操作数可转换为 true 时,这会导致 false 否则,表达式返回 true。 |

现在您已经对三种可用的逻辑操作符有了一个概念,让我们来看几个成熟的工作示例。考虑清单 3-2 中使用& &操作符的代码。

清单 3-2。逻辑运算符的示例
var result;

result = (true && true);
console.log("( true && true ) returns ", result);

result = ( false && true);
console.log("( false && true ) returns  ", result);

result = (false && false );
console.log ("( false && false ) returns ", result);

result = ( 'a' && 'b');
console.log ("( a && b ) returns ", result);

result = ( false && 'a' );
console.log ("( false && a ) returns ", result);

result = 'a' && true;
console.log ("( a && true ) returns ", result);

这个例子在许多操作数上使用&&运算符,包括布尔和非布尔。web 浏览器控制台中清单 3-2 的输出如图 3-2 所示。

A394309_1_En_3_Fig2_HTML.jpg

图 3-2。程序输出

如您所见,当涉及到布尔值时,结果总是布尔值。然而,非布尔操作数会产生奇怪的结果。清单 3-3 展示了一个涉及逻辑 OR 和 NOT 操作符的例子。

清单 3-3。逻辑 AND 和 NOT 运算符的用法
var result;

result = (true || true);
console.log("( true || true ) returns ", result);
result = (false || true);
console.log("( false || true ) returns ", result);
result = (false || (6 >= 4 ) );
console.log("( false || (6 >= 4 ) ) returns ", result);
result = ( 'a' || D );
console.log("( a || D ) returns ", result);
result = ( false || 'a' );
console.log("( false || a ) returns ", result);
result = ( ! false );
console.log("( ! false ) returns ", result);
result = ( ! true );
console.log("( ! true ) returns ", result);

列表 3-3 的输出如图 3-3 所示。

A394309_1_En_3_Fig3_HTML.jpg

图 3-3。显示 AND 和 NOT 运算符的输出

此示例使用了带有运算符的布尔值和非布尔值。在非布尔值的情况下,非布尔值是运算符使用的结果。

逻辑表达式从左到右计算。当一个为真的表达式与任何其他表达式进行“或”运算时,JS 会将整个表达式评估为真,而不执行任何后续评估:

true || *any_expression          evaluated as     true* 

另一方面,当 false 表达式与任意数量的表达式进行“与”运算时,逻辑运算将返回 false:

false && *any_expression       evaluated as*     false

这就是所谓的短路评估(或者麦卡锡评估)。

按位运算符

JavaScript 还支持许多位操作符。按位运算符将其操作数视为带符号的 32 位序列,采用二进制补码,由 1 和 0 组成(即二进制表示),而不是小数或十六进制数。但是,一旦执行了 operator 函数,就会返回 JS 数字值。各种按位运算符如表 3-3 所示。

表 3-3。按位运算符
|

操作员描述

|

操作员

|
| --- | --- |
| 和 | & |
| 运筹学 | | |
| 异或 | ^ |
| 不 | 你是谁 |
| 左移位 | << |
| 有符号右移(符号传播右移) | >> |
| 无符号右移(零填充右移) | >>> |

为了使用这些操作符,你必须理解操作数是如何存储和解释的。对于表 3-3 中的所有运算符,操作数被视为 32 位二进制数,然后各自的运算应用于一个或多个操作数。在这种格式中,最左边的位是符号位。该位为 1 或 0。0 表示正数,而 1 表示负数。

让我们检查两个例子,一个正的和一个负的,以及它们是如何被表示为 32 位二进制数值的。首先,让我们看看一个正数是如何存储的。例如,数字+10 表示为

00000000 00000000 00000000 00001010

另一方面,数字+2 显示为

00000000 00000000 00000000 00000010

现在让我们看看负数是如何存储的。数字-11 存储如下:

11111111 11111111 11111111 11110101               =    -11

按位 AND

按位 AND 运算符(&)对两个操作数(即它们的 32 位表示)的每一位执行 AND 运算。如果两个操作数的对应位等于 1,则结果的对应位为 1。否则,结果位被设置为 0。

语法是

A & B;

在下面的例子中,两个数字(2 和 10)进行 and 运算:

var num = 2 & 10 ;  // result is number 2

让我们看看这是如何工作的。下面显示了数字 2 和 10 的 32 位二进制表示形式,以及按位 and 运算后的结果数字:

00000000 00000000 00000000 00000010               =     2
00000000 00000000 00000000 00001010               =     10
--------------------------------------------------------------
00000000 00000000 00000000 00000010               =     2    =  2 & 10

正如您所看到的,两个操作数最右边的位等于 0,因此结果在相应的位置也包含 0。因为两个操作数在倒数第二位位置都包含 1,所以在 AND 运算后,结果位被设置为 1。

按位或

按位 or 运算符(|)对两个 32 位数字等效操作数的每一位执行 OR 运算。如果发现至少有一位为 1,则结果的相应位为 1。否则,结果位被设置为 0。语法是

A | B;

以下是按位 OR 运算符的一个示例:

var num = 2 | 10 ;  //  result is 10

下面显示了数字的 32 位二进制表示形式,以及按位“或”运算后的结果数字:

00000000 00000000 00000000 00000010               =     2
00000000 00000000 00000000 00001010               =     10
--------------------------------------------------------------
00000000 00000000 00000000 00001010               =     10    =  2 | 10

正如您所看到的,两个操作数最右边的位等于 0,因此结果在相应的位置也包含 0。因为两个操作数在倒数第二位都包含 1,所以在 OR 运算后,结果位被设置为 1。至少有一位(在第一个或第二个操作数中)等于 1 的位置,其结果位也设置为 1。

按位异或

按位异或(XOR)运算符(^)有点类似于 OR 运算符。只有当操作数中的一位为 1,另一位为 0 时,结果数中的位才会设置为 1。当发现只有一位为 1 时,结果的相应位为 0。在所有其他情况下,结果位设置为 0。语法是

A ^ B;

以下是 XOR 运算符的一个示例:

var num = 2 ^ 10 ;

让我们看看这是如何工作的。下面显示了数字 2 和 10 的 32 位二进制表示,以及按位异或运算后的结果数字:

00000000 00000000 00000000 00000010               =     2
00000000 00000000 00000000 00001010               =     10
--------------------------------------------------------------
00000000 00000000 00000000 00001000               =     8    =  2 ^ 10

正如您所看到的,两个操作数最右边的位等于 0,因此结果在相应的位置也包含 0。因为两个操作数在倒数第二位位置都包含 1,所以在异或运算后,结果位被设置为 0。

按位非

按位 NOT 运算符(∾)是一元运算符,这意味着它只涉及一个操作数。它只是对操作数中的位求反。每个 0 位变成 1,反之亦然。语法是

∼ A

以下是按位非运算符的一个示例:

var num = ∼ 10;

下面显示了数字 3 的 32 位二进制表示,以及 NOT 运算后的结果数字:

00000000 00000000 00000000 00001010               =     10

--------------------------------------------------------------
11111111 11111111 11111111 11110101               =    -11   =  ∼ 10

正如您所看到的,NOT 运算反转了操作数的所有位,包括符号位。这导致值为-11。

为了总结到目前为止所讨论的内容,表 3-4 给出了一个真值表,显示了各种按位运算符。

表 3-4。AND、or 和 XOR 运算符的真值表
|

操作数 A 中的位

|

操作数 B 中的位

|

AND 之后的结果位

|

OR 之后的结果位

|

异或运算后的结果位

|
| --- | --- | --- | --- | --- |
| Zero | Zero | Zero | Zero | Zero |
| Zero | one | Zero | one | one |
| one | Zero | Zero | one | one |
| one | one | one | one | Zero |

按位左移

顾名思义,按位左移运算符(<

A << B

考虑以下示例:

var result = ( 10  << 2  ); // left shift by two places

在这种情况下,移位前的数字 10 显示为

00000000 00000000 00000000 00001010

向左移动两个位置后,二进制表示如下所示:

00000000 00000000 00000000 00101000

左边加了两个零。这个结果现在是十进制数 40。

按位无符号右移

按位无符号右移位运算符(>>>)也称为零填充右移位。不管操作数的符号是什么,它总是产生一个非负值。语法是

A >>> B ;

它将操作数 A 的位移动 B 指定的位数,右移的位会丢失,这些位等于 B)。在左侧,添加的零等于移位的位数(即 B)。在操作之后,最左边的位总是等于零(即,导致非负值)。考虑以下示例:

var result = ( 10  >>> 2  ); // right shift by two places

在这种情况下,移位前的数字 10 如下所示:

00000000 00000000 00000000 00001010

向右移动两个位置后,二进制表示如下所示:

00000000 00000000 00000000 00000010

在左边,添加了两个零。这个结果现在是十进制数 2。

按位带符号右移

按位有符号右移运算符(>>),也称为符号传播右移,将位向右移动。然而,数字的符号也被保留。向右移动的位数由符号位填充,无论是 0 还是 1。语法是

A >> B ;

考虑以下示例:

var result = ( -10 >> 2 ); //  signed right shift  result  = -3

在这段代码中,在执行语句后,结果变量包含值-3。

编码示例

既然您已经熟悉了各种位操作符,清单 3-4 展示了一个完整的编码示例。

清单 3-4。按位运算符示例
var result;
result = ( 2 & 10 );  //  AND
console.log("( 2 AND 10 ) returns ", result);

result = ( 10 | 2 ); // OR
console.log("( 10 OR 2 ) returns  ", result);

result = ( 10 ^ 2 ); // XOR
console.log ("( 10 XOR 2 ) returns ", result);

result = ( ∼ 10 );  // NOT
console.log ("( NOT 10 ) returns ", result);

result = ( 10  << 2  ); // left shift by two
console.log("( 10  << 2  ) returns  ", result);

result = ( -10 >> 2 ); //  signed right shift
console.log ("( -10 >> 2 ) returns ", result);

result = ( 10 >>> 2 );  // unsigned right shift
console.log ("( 10 >>> 2 ) returns ", result);

该程序的输出如图 3-4 所示。

A394309_1_En_3_Fig4_HTML.jpg

图 3-4。程序输出

赋值运算符

JavaScript 还支持许多赋值操作符。赋值运算符可以简单地定义为考虑到右操作数的值而将值“赋值”给左操作数的运算符。

各种赋值运算符如表 3-5 所示。

表 3-5。赋值运算符
|

操作员

|

运算符用法/速记

|

实际效果

|
| --- | --- | --- |
| 分配(基本分配) | x = y | x = y |
| 加法赋值 | x += y | x = x + y |
| 减法赋值 | x -= y | x = x - y |
| 乘法赋值 | x *= y | x = x * y |
| 分部分配 | x /= y | x = x / y |
| 余数分配 | x %= y | x = x % y |
| 指数赋值 | x **= y | x = x ** y |
| 左移赋值 | x <<= y | x = x << y |
| 右移位赋值 | x >>= y | x = x >> y |
| 无符号右移位赋值 | x >>>= y | x = x >>> y |
| 按位 AND 赋值 | x &= y | x = x & y |
| 按位异或赋值 | x ^= y | x = x ^ y |
| 按位 OR 赋值 | x |= y | x = x | y |

如您所知,基本的赋值操作符(=)将右边操作数的值赋给左边的操作数。其余的操作符是本章到目前为止讨论的各种操作符的简写。例如,考虑以下情况:

x &= y

这段代码只是以下代码的简写形式:

x = x & y

考虑下面的代码块:

var result = 2;
result  &=  10;

此代码与相同

var result = 2 & 10;

但是,要确保赋值操作符中没有空格,在本例中为&=。将它写成& =会产生语法错误。

字符串运算符

到目前为止,在这一章中,你已经看到运算符+被用作算术运算符。但是,当与字符串一起使用时,+运算符的作用相当于提供串联功能的字符串运算符。在第二章中,你看到了许多这种用于数字和/或字符串的例子。

摘要

本章首先详细解释了 JavaScript 提供的算术运算符。然后介绍了比较运算符和逻辑运算符的用法,接着详细解释了按位运算符。最后,您看到了各种赋值操作符,它们被用作 JavaScript 支持的各种位、逻辑和算术操作符的简写。JavaScript 的学习之旅还在继续,在下一章中,你将看到 JS 领域中主要使用的控制结构的细节。

四、JavaScript 中的控制结构

本章描述了 JS 语言中的各种控制结构,并演示了如何使用它们来满足需求。本章首先概述了 JavaScript 支持的块语句。接下来,如果...详细介绍了 else 和 switch 语句。然后将向您介绍 JavaScript 支持的各种类型的循环,包括 for 和 while 循环,并给出展示如何执行它们的演示程序。本章最后简要介绍了标签声明。

块语句

块用于对一组语句进行分组。一个块用一对大括号{}括起来。基本语法是

{
  st_1;
  st_2;
}

Block 语句用在各种控制结构中。这些包括 if 语句和 while 和 for 循环(将在本章的后半部分介绍)。考虑以下示例:

var abc = 0;
while ( abc < 122) {
  abc = abc + 2;
}

在这段代码中,{ ABC = ABC+2;}是 block 语句。

考虑另一个块的例子:

var abc = 150;
{
  var abc = 100 + 2;
}
alert(abc); // outputs 102

此代码输出 102,因为第二个 var 语句(在花括号内)与该块之前的 var 语句位于相同的范围内。

清单 4-1 展示了在一个块中使用复合语句的例子。

清单 4-1。块示例
<html>
   <body>
      <script>
         {
         var x = 5;
          x++;
          }
          console.log(x);
      </script>
   </body>
</html>

程序的输出如图 4-1 所示。

A394309_1_En_4_Fig1_HTML.jpg

图 4-1。字块输出

条件语句

JavaScript 提供了两种条件语句:

  • 如果...其他

  • 转换

这些语句允许您在发现给定条件为真时执行代码块。或者,在 if 语句的情况下,当发现条件为假时,可能会执行语句块。

如果...else 语句

当发现逻辑条件为真时,if 语句执行一组语句。可选的 else 子句用于在条件被确定为假时执行语句。关于简单 if 语句的流程图如图 4-2 所示。

A394309_1_En_4_Fig2_HTML.jpg

图 4-2。if 语句流程图

if 语句的语法是

if (eval_of_condition) {
  first_block;
} else {
  second_block;
}

任何导致 true 或 false 的表达式都可以用来表示条件。如果发现条件为真,则执行 first _ block 否则,执行 second_block。该块可以包含任意数量的语句,包括更多的 if 语句。

还可以使用 if 和 else if 来指定多个要逐个检查的条件,以便按顺序测试多个条件,如下所示:

if (eval_cond1) {
  block_1;
} else if (eval_cond2) {
  block_2;
} else if (eval_cond3) {
  block_3;
} else {
  last_block;
}

当指定多个条件时,将执行与评估为真的第一个条件相关的代码。如果发现第一个条件为假,则检查由 else if 指定的下一个条件,然后检查下一个 else if,依此类推。如果三个条件都为假,则执行 last_block 代码。

注意

值 false、null、undefined 和 0 在计算时总是产生“false”值。

清单 4-2 展示了如何使用 if 语句创建一个短程序。

清单 4-2。使用 if 语句的驾驶执照程序
<html>
   <body>
      <script>
         var age = 20;
         if( age > 18 )
          {
               console.log("Eligible for Driving license");
            }
      </script>
   </body>
</html>

该示例显示了一个简单的 if 语句。声明了值为 20 的变量 age。if 语句中的条件声明,如果 age 大于 18,则应该执行代码块。该程序的输出如图 4-3 所示。

A394309_1_En_4_Fig3_HTML.jpg

图 4-3。程序输出

清单 4-3 通过修改示例添加了一个 else 子句,使事情变得有点复杂。

清单 4-3。带 else 子句的驾驶执照计划
<html>
   <body>
      <script>
            var age = 18;
            if( age > 18 ){
               console.log("Eligible for Driving license");
            }
            else if( age == 18 ){
                console.log("Eligible for learning license");
            }
            else{
                console.log("Not eligible for Driving license");
            }
      </script>
   </body>
<html>

在这种情况下,执行与满足的条件相关的代码块,并通过 console.log 语句打印相应的输出。在本例中,else if 条件(即年龄== 18)得到满足,因此输出将有资格获得学习许可,如图 4-4 所示。

A394309_1_En_4_Fig4_HTML.jpg

图 4-4。程序输出

交换语句

switch 语句使您能够计算一个表达式,然后使用许多 case 标签匹配它的值。当发现匹配时,执行相关的代码块。

在开关控制结构中使用了 break 语句。break 语句确保一旦表达式匹配,程序就脱离 switch。

开关控制结构的流程图如图 4-5 所示。

A394309_1_En_4_Fig5_HTML.jpg

图 4-5。开关控制结构流程图

交换机控制结构的语法是

switch (expression) {
  case value1:
    //Statements executed when the result of expression matches value1
    [break;]
  case value2:
    //Statements executed when the result of expression matches value2
    [break;]
  ...
  default:
    //Statements executed when none of the values match the value of the expression
    [break;]
}

表达式的结果值与每个大小写值相匹配。如果没有一个大小写值与表达式的大小写值匹配,则执行默认的块代码。

清单 4-4 提供了驾驶执照程序中 switch 语句的一个例子。

清单 4-4。switch 语句示例
<html>
<body>
<script>
var age = "16";
switch (age) {
    case "18":
        console.log("Eligible for learning license")
        break;
    case "20":
        console.log("Eligible for two wheeler license")
        break;
    case "23":
        console.log("Eligible for four wheeler license")
        break;
    default:
    console.log("Not eligible for license");
}
</script>
</body>
</html>

可变年龄声明为 16 岁。不同的 case 子句包含在各自的编码中。清单 4-4 还包括一个默认子句,指定如果没有匹配的值(通过 case 子句指定)程序应该做什么。因为年龄是 16 岁,所以执行默认代码。程序输出如图 4-6 所示。

A394309_1_En_4_Fig6_HTML.jpg

图 4-6。Switch 语句输出

如前所述,正确执行开关控制结构需要 break 语句。清单 4-5 显示了一个没有 break 语句的开关控制结构的例子。

清单 4-5。不正确的开关控制结构示例
<!DOCTYPE html>
<html>
<body>
<script>
var color = "Green";
switch (color) {
    case "Red":
        console.log("Sign for Danger");
    case "Green":
        console.log("Sign for Growth");
    case "White":
        console.log("Sign for Peace");
    default:
    console.log("No sign");
}
</script>
</body>
</html>

由于清单 4-5 中省略了 break 语句,输出显示不正确,如图 4-7 所示。

A394309_1_En_4_Fig7_HTML.jpg

图 4-7。错误输出

提供给开关表达式的值为绿色。这与第二个 case 子句相匹配,因此在控制台日志中应该只显示增长符号。但是,因为没有包含 break 语句,所以在执行匹配的语句后,还会执行两个后续的 case 子句。

JavaScript 中的循环

循环有助于多次或重复执行代码块,直到给定的条件为真。JS 支持各种类型的循环:

  • while 循环

  • 做...while 循环

  • for 循环

  • 为...在回路中

while 循环

这是一个条件循环。while 循环执行一个代码块,直到指定的条件评估为 true。一旦条件失败,循环就会停止。while 循环的流程图如图 4-8 所示。

A394309_1_En_4_Fig8_HTML.jpg

图 4-8。while 循环流程图

while 循环的一般语法是

while (condition)
{
    Statements to be executed if condition is true
}

清单 4-6 提供了一个 while 循环的完整工作示例。

清单 4-6。while 循环示例
<html>
   <body>
      <script>
            var n = 0;
            console.log("Starting Loop ");
          while (n < 3)
        {
            console.log("Current Count : " + n + " ");
            n++;
         }
      console.log("Loop stopped!");
      </script>
   </body>
</html>

清单 4-6 声明了变量 n 并给它赋值 0。while 循环条件规定变量 n 应该小于 3。在循环中,n 递增 1。因此,循环继续三次;也就是说,对于 n 等于 0,1 和 2。一旦 n 的值等于 3(即满足条件),循环就停止。

程序的输出如图 4-9 所示。

A394309_1_En_4_Fig9_HTML.jpg

图 4-9。while 循环的输出

做...while 循环

do...while 循环重复进行,直到指定的条件被评估为 false。首先指定代码块,然后执行相关条件。这意味着循环将总是至少执行一次,即使条件为假。流程图如图 4-10 所示。

A394309_1_En_4_Fig10_HTML.jpg

图 4-10。do 流程图...while 循环

do 的语法...while 循环是

do
{
  //Statements;
}
while (condition);

do 的一个例子...while 循环如清单 4-7 所示。

清单 4-7。做...while 示例
<html>
   <body>
      <script>
            var n = 0;
            console.log("Starting Loop ");
          do
        {
            console.log("Current Count : " + n + "");
            n++;
         }
      while (n < 4)
      console.log("Loop stopped!");
      </script>
   </body>
</html>

在这个例子中,变量 n 的值被设置为 0。在每次循环迭代中,n 的值增加 1。while 循环重复,直到 n 的值不再小于 4(即,n 等于 4)。

列表 4-7 的输出如图 4-11 所示。

A394309_1_En_4_Fig11_HTML.jpg

图 4-11。do 输出...while 循环

for 循环

for 循环是一个条件循环,它会一直持续到指定的条件计算结果为 false 为止。通用语法是

for ([initialization]; [test condition]; [expression])
{
   Statement
}

在初始化部分,将循环计数器初始化为一个初始值。对于测试条件,您指定必须检查的条件,以确定循环是否应该继续。表达式是增加或减少计数器或值的部分。

清单 4-8 展示了一个在程序中使用 for 循环的例子。

清单 4-8。对于循环示例
<html>
   <body>
      <script>
            var count;
            console.log("Starting Loop" + "");
            for(count = 0; count < 10; count++){
               console.log("Current Count : " + count );
            }
            console.log("Loop stopped!");
      </script>
   </body>
</html>

此示例声明变量 count,然后在 for 循环中将 count 的值初始化为 0。然后,循环条件检查计数值是否小于 10。如果是,计数器加 1。

在循环迭代中,显示 count 的当前值。每次循环迭代后,计数值增加 1,并根据指定的条件检查其值。

该循环运行十次(计数等于 0 到 9)。当 count 的值等于 10 时,条件评估为 false,循环停止。

程序的输出如图 4-12 所示。

A394309_1_En_4_Fig12_HTML.jpg

图 4-12。程序输出

前面的例子向您展示了如何使用 for 循环来增加计数器值。清单 4-9 展示了另一个 for 循环示例,展示了如何递减计数器值。

清单 4-9。反向 for 循环
<html>
   <body>
      <script>
            var count;
            console.log("Starting Loop" + "");
            for(count = 10 ; count > 0; count--){
               console.log("Current Count : " + count );
            }
            console.log("Loop stopped!");
      </script>
   </body>
</html>

此示例显示反向循环计数。它首先将计数值初始化为 10。该条件检查 count 的值是否大于 0。每循环一次,count 的值就减 1。该程序的输出如图 4-13 所示。

A394309_1_En_4_Fig13_HTML.jpg

图 4-13。程序输出

如您所见,打印的第一个值是 10,因为 count 的初始值是 10。只要 count 的值大于 0,循环中的代码就会运行(因此最后打印的值是 1)。

在 for 循环代码块中,还可以包含 if 结构。假设您需要打印从 0 到 19 的所有偶数。您可以通过使用 for 循环和 if 语句的组合来实现这一点,如清单 4-10 所示。

清单 4-10。带有 if 语句的 for 循环
<html>
   <body>
      <script>
           var i;
            for(i = 0; i < 20; i++)
            {
               if((i % 2) == 0)
             {
               console.log("Number is divisible by 2 : " + i );
               continue;
              }
            }
      </script>
   </body>
</html>

此示例在 for 循环中使用 if 语句来检查变量 I 是否能被 2 整除。在 I 的值能被 2 整除的每种情况下,程序都会打印出该值。程序的输出如图 4-14 所示。

A394309_1_En_4_Fig14_HTML.jpg

图 4-14。程序输出

您也可以嵌套 for 循环,这意味着您可以在 for 循环中包含一个 for 循环。在讨论 for 之后,您将看到一个与 label 关键字结合使用的示例...在循环中。

注意

break 语句也可以在 for 循环中使用,以退出循环。

为...在回路中

森林...in 循环是一种特殊类型的循环,在对象的属性上运行。森林...in 循环在一个对象的所有属性上迭代指定的变量。

森林...在语法上是

for (variable in object) {
  statements
}

清单 4-11 提供了 for 的示例...程序中使用的 in 循环。

清单 4-11。为...在示例中
<html>
   <body>
      <script>
         var obj = {a:"alto", b:"scorpio", c:"zen"};
          for(var string=" " in obj) {
               console.log(obj[string]);
          }
      </script>
   </body>
</html>

清单 4-11 介绍了一个具有三个属性 a、b 和 c 的对象 obj,这三个属性分别被赋值为 alto、scorpio 和 zen。森林...然后使用 in obj 循环来处理对象的每个属性。在每次迭代中,object 的一个属性被赋给变量名,循环继续,直到 object 的所有属性都被读取。console.log 方法用于在 web 浏览器控制台上显示属性内容。

程序的输出如图 4-15 所示。

A394309_1_En_4_Fig15_HTML.jpg

图 4-15。打印对象的属性

标签语句

label 语句使您能够为语句块定义唯一的标识符。语法是

label:
  statements

标签名称后面跟一个冒号,标签下面是与标签名称链接的语句块(或由给定标签定义的语句块)。为了澄清,考虑清单 4-12 中的例子。

清单 4-12。标签示例
<html>
   <body>
      <script>
         var i, j;
       Outerloop:
           for (i = 0; i < 5; i++) {
           for (j = 0; j < 5; j++) {
                 if (i === 1 && j === 1) {
                         break Outerloop;
      }
      console.log("i = " + i + ", j = " + j);
   }
}
      </script>

   </body>
</html>

清单 4-12 为外部 for 循环定义了一个标签 Outerloop。外循环的每次迭代还有一次内循环运行。为了在计数器 I 和 j 的值都等于 1 时退出外部循环,break 语句与先前定义的标签 outer loop 一起使用,以表示外部 for 循环。列表 4-12 的输出如图 4-16 所示。

A394309_1_En_4_Fig16_HTML.jpg

图 4-16。程序输出

摘要

本章涵盖了 JS 语言中的各种控制结构,并描述了如何使用它们来满足需求。它从 JavaScript 支持的块语句开始。接下来,它讨论了如果...else 和 switch 语句。最后,演示程序向您展示了如何执行 JavaScript 中支持的各种类型的循环,包括 for 和 while 循环,以及 LABEL 语句。

第五章讨论了 JavaScript 中的另一个重要话题:正则表达式和字符串方法。

五、正则表达式和字符串方法

本章向您介绍 JS 的一个重要特性:正则表达式处理。您可以使用此功能在给定的文本流中查找和替换与给定模式匹配的文本。本章首先解释了 JavaScript 中定义的正则表达式。然后向您展示如何将 RegExp 与字符串方法结合使用。本章的后半部分将向您介绍 RegExp 对象的属性和方法。

正则表达式:概述

正则表达式由用于匹配文本字符串中的字符组合的模式(以及可选的修饰符)组成。正则表达式提供了一种执行所有类型的字符串搜索和替换的方法。在 JavaScript 中有两种方法定义正则表达式对象。第一个显示在这里:

var pattern = new RegExp(pattern, attributes);

另一种方式如下所示:

var pattern = /pattern/attributes or modifiers;

它由一个模式和一个或多个可选标志(即修饰符或属性)组成。模式指示要匹配的正则表达式模式,而属性或修饰符指定任何附加信息。顾名思义,修饰符用于修改相关文本中的模式搜索。可以指定为属性的值有

  • g:全局修饰符。在字符串中搜索给定模式的所有匹配项。

  • I:忽略模式搜索中区分大小写的行为。

  • m:多行修改器。正则表达式中指定的任何^或$都适用于字符串的每一行。如果没有这个修饰符,它只适用于整个字符串一次。

在正则表达式模式中,有元字符和量词。元字符是用于定义搜索模式的特殊含义字符。一些常用的元字符如表 5-1 所示。在要处理的文本字符串中,由元字符标识的子字符串可能会出现几次。

表 5-1。元字符
|

元字符

|

目的

|
| --- | --- |
| 。 | 搜索字符 |
| \s | 搜索空白字符 |
| \S | 搜索非空白字符 |
| \w | 搜索字母数字字符,如 1、2、A、A、h、d 等。(即单词字符,表示 a-z、A-Z 或 0-9 中的字符,包括下划线字符,_) |
| \W | 搜索非字母数字字符,如%、#、%(即非单词字符) |
| \d | 搜索数字,如 1、2 或 3。 |
| \D | 搜索非数字字符,如*、#、a 和 b。 |

量词用于指定特定字符或字符集的出现次数。表 5-2 列出了一些常用的量词。

表 5-2。量词
|

数量词

|

目的

|
| --- | --- |
| p+ | 匹配至少一个 p 的出现。 |
| p* | 匹配 p 的零次或多次出现。 |
| p? | 检查一个字符串是否包含零个或一个 p。 |
| p{A} | 匹配多个 p 的序列,例如,ab{2}将匹配 abab。 |
| p{A,B} | 检查一个字符串是否有一个从 A 到 B 的 p 数序列。 |
| p{A,} | 检查一个字符串是否至少有 p 个数的序列,例如,ab{1,}将匹配 ab,abab,依此类推。 |
| p 美元 | 匹配以 p 结尾的字符串。例如,b$将匹配 ab、b 和 cab。 |
| p | 匹配以 p 开头的字符串。例如,^a 将匹配 ab、ah 和 aj。 |

您可以在 regex 模式中使用方括号来指定要搜索的字符。表达式中方括号的典型用法如表 5-3 所示。

表 5-3。表达式中方括号的用法
|

表示

|

目的

|
| --- | --- |
| [xyz] | 搜索方括号中显示的任何字符 |
| [^xyz] | 搜索除括号中的字符以外的任何字符 |
| [A-B] | 搜索范围在 A 到 B 之间的数字 |
| [^A-B] | 查找范围 A 到 B 之外的任何数字 |
| (甲|乙) | 类似于 OR,搜索字符 a 或 b |

注意

如何编写正则表达式的详细解释超出了本章的范围。然而,我们将把重点放在 JS 方法上,这些方法允许您编写正则表达式来解决典型的用户需求。

有两种方法可以使用正则表达式:

  • 使用字符串对象方法

  • 使用正则表达式对象(RegExp 对象)的属性和方法

下面几节将依次介绍每一种方法。以下是正则表达式的一些示例:

var regex = /High/i ;
var regex = /[C-G]/gi ;
var re = /\s*;\s*/;
var text = new RegExp("Good morning", "g");

字符串方法

在 JavaScript 中,以下是与正则表达式处理相关的字符串方法:

  • 搜索

  • 替换

  • 比赛

  • 使分离

接下来将逐一介绍这些字符串方法,并附有示例。

搜索方法

search 方法使用表达式来搜索匹配项,并返回匹配项的位置。search()方法的语法是

str.search(regexp)

返回值将是第一个匹配的索引。清单 5-1 中显示了一个简单的例子。

清单 5-1。search()方法示例
<html>
   <body>
      <script>
         var text = "Visit the Google";
         console.log(text.search("Google"));
      </script>
   </body>
</html>

清单 5-1 用一些文本声明了变量 text(“访问 Google”)。text.search()方法在可变文本中搜索“Google ”,并返回它的给定位置。console.log()方法用于显示输出。

列表 5-1 的输出如图 5-1 所示。

A394309_1_En_5_Fig1_HTML.jpg

图 5-1。程序输出

替换方法

顾名思义,replace 方法用另一个(新的)子字符串替换文本中与给定正则表达式模式匹配的子字符串。然后返回修改后的字符串。replace()方法的语法是

str.replace(regexp, newsubstr)

返回值将是新字符串,其中一个或多个给定模式的匹配项将被相应地替换。考虑清单 5-2 中的例子。

清单 5-2。replace()方法示例
<html>
   <body>
      <script>
         var text = "High level language";
         console.log(text.replace(/High/i, "Low"));
      </script>
   </body>
</html>

在清单 5-2 中,text.replace()方法用于将字符串“High”替换为“Low”。修饰语 I 用来忽略这种情况。

列表 5-2 的输出如图 5-2 所示。

A394309_1_En_5_Fig2_HTML.jpg

图 5-2。输出
注意

也可以在要匹配的模式中指定子组。使用 replace 方法,可以使用占位符$1 和$2 来寻址这些子组。例如:

var regex = /(\d+)\s(\d+)/; 
var string1 = "123 321";   var newstring = string1.replace(regex, "$2, $1"); 

匹配方法

match 方法用于以数组的形式获取给定文本字符串中的所有子字符串(正则表达式匹配)。如果找不到匹配项,使用此方法将返回 null。match()方法的语法是

str.match(regexp)

清单 5-3 展示了匹配方法如何工作的一个例子。

清单 5-3。match()方法示例
<html>
   <body>
      <script>
         var text = "Advance varsion of JavaScript 7.1.4";
         var result = text.match(/va/g)
         console.log(result);
      </script>
   </body>
</html>

此示例用字符串值声明变量 text。然后使用 text.match()方法将字符“va”与字符串值进行匹配。列表 5-3 的输出如图 5-3 所示。

A394309_1_En_5_Fig3_HTML.jpg

图 5-3。输出

列表 5-4 显示了匹配方法的另一个例子。

清单 5-4。另一个 match()方法示例
<html>
   <body>
      <script>
        var text = "ABCDEFG12345abcdefghijklm";
         var result = text.match(/[C-G]/gi)
         console.log(result);
      </script>
   </body>
</html>

该示例演示了在 match()方法中使用 global (g)和 ignore (i) case 修饰符/标志。它声明了变量 text,并给它赋了一个文本值。text.match()方法用于查找从 C 到 G 和/或 C 到 G 的所有字母,然后将结果返回到数组 result 中。

列表 5-4 的输出如图 5-4 所示。

A394309_1_En_5_Fig4_HTML.jpg

图 5-4。输出

拆分方法

在正则表达式的上下文中,split 方法用于将一个字符串拆分为一个子字符串数组,这些子字符串与给定的正则表达式模式相匹配。拆分方法的语法是

str.split(regex, Limit)

如果不使用正则表达式,可以指定分隔符来代替正则表达式。语法将看起来像这样

str.split(separator, limit)

如前所述,返回值将以数组的形式出现。该限制是一个数字(例如,2、10 等。)指定结果数组中包含的最大元素数。分隔符和限制(整数)都是可选的。

清单 5-5 展示了一个使用 split 方法从字符串中删除空格的例子。

清单 5-5。拆分方法示例
<html>
<body>
      <script>
        var countries = "UK ; US; Europe;  India";
        console.log(countries);
        var re = /\s*;\s*/;
        var countriesList = countries.split(re);
        console.log(countriesList);
      </script>
   </body>
</html>

这个例子声明了变量 countries,并给它分配了一些国家名,用分号(;)包含在空格内。正如您所看到的,split 方法中使用的正则表达式模式查找零个或多个空格,后跟一个分号,然后又是零个或多个空格。当在变量 countries 中发现这种模式时,将执行拆分,并从结果子字符串中删除空格和分号。对于每个匹配,数组元素被填充。countriesList 是作为拆分结果返回的数组。

清单 5-5 的输出如图 5-5 所示,显示了原始字符串和结果数组。

A394309_1_En_5_Fig5_HTML.jpg

图 5-5。输出

清单 5-6 显示了 split 方法的另一种用法,它使用了可选的有限数量的 split。

清单 5-6。另一个 split()方法示例
<html>
   <body>
      <script>
        var myString = 'Hello, this is JavaScript coding';
        var splits = myString.split(' ', 1);
        console.log(splits);
      </script>
   </body>
</html>

在这个例子中,split 将在字符串 myString 中查找空格,并在找到第一个匹配时停止。列表 5-6 的输出如图 5-6 所示。

A394309_1_En_5_Fig6_HTML.jpg

图 5-6。程序输出

正则表达式对象

既然您已经熟悉了正则表达式对象的基础,本节将深入研究它的各种属性和方法的细节。

正则表达式对象属性

表 5-4 显示了正则表达式对象的属性。

表 5-4。正则表达式对象属性
|

财产

|

描述

|
| --- | --- |
| 构造器 | 包含创建对象原型的函数。 |
| 全球的 | 指定是否为给定的正则表达式设置了 g 修饰符。 |
| ignoreCase | 指定是否为给定的正则表达式设置了 I 修饰符。 |
| loadIndex | 指定开始下一个匹配的索引。 |
| 多线 | 指定是否为给定的正则表达式设置了 m 修饰符。 |
| 来源 | 表示要搜索的模式的文本。 |

构造函数属性

构造函数属性包含对创建对象实例的函数的引用。构造函数用法的语法是

RegExp.constructor

对于正则表达式,构造函数属性返回函数 RegExp(){[本机代码] }。

注意

constructor 属性适用于其他对象,如数字和字符串。对于数字,constructor 属性返回函数 Number(){[本机代码] }。对于字符串,它返回函数 String(){[本机代码] }。

清单 5-7 提供了一个构造器属性如何工作的例子。

清单 5-7。构造函数属性示例
<html>
   <body>
      <script>
               var text = new RegExp("Good morning", "g");
               console.log("text.constructor is:" + text.constructor);
      </script>
   </body>
</html>

列表 5-7 的输出如图 5-7 所示。

A394309_1_En_5_Fig7_HTML.jpg

图 5-7。程序输出

清单 5-8 显示了另一个构造函数属性的例子。

清单 5-8。构造函数属性示例
<html>
   <body>
      <script>
               var num = new Number(6);
               console.log("num.constructor is:" + num.constructor);
      </script>
   </body>
</html>

列表 5-8 的输出如图 5-8 所示。

A394309_1_En_5_Fig8_HTML.jpg

图 5-8。程序输出

全局属性

global 属性指定正则表达式是否使用全局修饰符(即是否设置了 g 修饰符)。访问全局属性的语法是

RegExp.global

如果设置了 g 修饰符,则该属性返回 true,否则返回 false。参见清单 5-9 中的示例。

清单 5-9。全局属性示例
<html>
   <body>
      <script>
               var text = "Learn JavaScript";
               var pattern1 = /Java/g;
                var result = pattern1.global;
               console.log("Text is matched with Java:" + pattern1.global);
                var pattern2 = /Java/
                console.log("Text is matched with Java:" + pattern2.global);
      </script>
   </body>
</html>

清单 5-9 的输出如图 5-9 所示。

A394309_1_En_5_Fig9_HTML.jpg

图 5-9。输出

ignoreCase 属性

ignoreCase 属性指定正则表达式是否执行不区分大小写的匹配(换句话说,是否设置了 I 修饰符)。访问该属性的语法是

RegExp.ignoreCase

如果设置了 I 修饰符,ignoreCase 属性返回 true,否则返回 false。

清单 5-10 给出了 ignoreCase 属性用法的一个简单例子。

清单 5-10。ignoreCase 属性示例
<html>
   <body>
      <script>

               var pattern1 = /Java/i;
               console.log("IgnoreCase property is set:" + pattern1.ignoreCase);
               var pattern2 = /Java/;
               console.log("IgnoreCase property is set:" + pattern2.ignoreCase);
      </script>
   </body>
</html>

这个例子首先声明正则表达式模式 pattern1。在这种情况下,指定 I 修饰符,使其忽略大小写。接下来,该示例声明不带 ignoreCase 修饰符的 pattern2 /Java/在这两种情况下,都会为 ignoreCase 属性生成使用 console.log 方法的输出,如图 5-10 所示。

A394309_1_En_5_Fig10_HTML.jpg

图 5-10。输出

lastindexof 属性

lastIndex 属性指定在 RegExp.exec()和 RegExp.test()方法找到的最后一个匹配项之后,给定文本字符串中的字符位置。例如,如果找到的匹配项是“Java ”,其中第二个“a”位于文本字符串中的第 14 个位置,则 lastIndex 值将被设置为 15。仅当设置了 g 修饰符时,此属性才适用。如果找不到匹配项(或另一个匹配项),exec()和 test()方法会将该属性重置为 0。

lastindexof 的语法是

RegExp.ignoreCase

清单 5-11 中显示了 lastIndex 属性的一个示例。

清单 5-11。lastIndex 属性示例
<html>
   <body>
      <script>
                var text = "We can use JavaScript in Java coding";

                var pattern = /Java/g;

                var result = pattern.test(text);
                console.log("Current index:" + pattern.lastIndex);

                var result = pattern.test(text);
                console.log("Current index:" + pattern.lastIndex);
      </script>
   </body>
</html>

此示例包含一个文本字符串和一个使用全局修饰符的正则表达式。它使用 test 方法两次,每次都显示 lastIndex 属性。列表 5-11 的输出如图 5-11 所示。

A394309_1_En_5_Fig11_HTML.jpg

图 5-11。输出

多线属性

multiline 属性指定正则表达式是否执行多行匹配。它检查是否设置了 m 修饰符。multiline 的语法是

RegExp.multiline

如果设置了 m 修饰符,则属性返回 true,否则返回 false。清单 5-12 展示了多行属性的一个例子。

清单 5-12。多行属性示例
<html>
   <body>
      <script>
               var text = "Learn JavaScript";
               var pattern1 = /Java/m;
               var result = pattern1.multiline;
               console.log("Text is matched with Java:" + pattern1.multiline);
               var pattern2 = /Java/;
               console.log("Text is matched with Java:" + pattern2.multiline);
      </script>
   </body>
</html>

清单 15-12 的输出如图 5-12 所示。

A394309_1_En_5_Fig12_HTML.jpg

图 5-12。输出

源属性

source 属性包含 RegExp 模式的文本。源属性的语法是

RegExp.source

顾名思义,source 属性返回用于模式匹配的文本。它不返回正则表达式中使用的修饰符(如果有)。清单 5-13 显示了 source 属性的一个例子。

清单 5-13。源属性示例
<html>
   <body>
      <script>

        var pattern1 = /Java/g;
        console.log("Any text you have can be matched with the pattern:" + pattern1.source);
      </script>
   </body>
</html>

首先指定一个正则表达式模式 1。列表 5-13 的输出如图 5-13 所示。

A394309_1_En_5_Fig13_HTML.jpg

图 5-13。输出

正则表达式对象方法

RegExp 对象提供了四种方法,如表 5-5 中所列和所述。

表 5-5。正则表达式对象方法
|

方法

|

描述

|
| --- | --- |
| 执行() | 在参数字符串中搜索给定的正则表达式模式匹配 |
| 测试() | 类似于 exec,但当找到匹配项时返回 true,否则返回 false |
| toSource() | 返回表示指定对象的对象文字 |
| toString() | 返回表示指定对象的字符串 |

exec 方法

exec 方法在字符串中搜索与 RegExp 匹配的文本。exec 方法的一般语法是

RegExp.exec(string)

string 参数表示要搜索的字符串。如果找到匹配项,该方法将返回匹配的文本(对应于给定正则表达式的子字符串)。否则,返回 null。参见清单 5-14 中的示例。

清单 5-14。exec()方法示例
<html>
   <body>
      <script>
                var text = "Learn JavaScript its very interesting script";

                var pattern = new RegExp( "Java", "g" );
                var result = pattern.exec(text);
                console.log("Text is matched with Java:" + result);

                var pattern1 = new RegExp( "language", "g" );
                    result = pattern1.exec(text);
                console.log("Text is matched with language:" + result);
      </script>
   </body>
</html>

此示例首先声明一个文本变量,并分配一个要搜索的字符串。使用 new 关键字和内置的 RegExp 对象声明了两个模式,即模式 1 和模式 2。对于变量 pattern1 和 pattern2,使用相同的“文本”字符串调用方法 exec。然后在变量 result 中返回结果。

清单 15-14 的输出如图 5-14 所示。

A394309_1_En_5_Fig14_HTML.jpg

图 5-14。输出

检测方法

测试方法还在给定的字符串中搜索匹配正则表达式模式的文本。如果找到匹配,则返回 true。否则,它返回 false。test()的语法是

RegExp.test( string )

测试方法将一个字符串参数作为输入,如清单 5-15 所示。

清单 5-15。测试方法示例
<html>
   <body>
      <script>
               var text = "Learn JavaScript its very interesting script";

               var pattern = new RegExp( "Java", "g" );
               var result = pattern.test(text);
               console.log("Text is matched with Java:" + result);

               var pattern = new RegExp( "language", "g" );
               var result = pattern.test(text);
               console.log("Text is matched with language:" + result);
      </script>
   </body>
</html>

清单 15-5 的输出如图 5-15 所示。

A394309_1_En_5_Fig15_HTML.jpg

图 5-15。输出

toString 方法

toString 方法以 regex 文本的形式返回正则表达式的相应字符串表示。返回的字符串包含在反斜杠中,如果适用,还包括修饰符。toString()的语法是

RegExp.toString(string )

清单 15-16 展示了 toString 方法的一个实例。

清单 5-16。toString()方法示例
<html>
   <body>
      <script>
                var text ;
                var pattern = new RegExp( "Java", "g" );
                var result = pattern.toString(text);
                console.log("Return value:" + result);

                var pattern = new RegExp( "/", "g" );
                var result = pattern.toString(text);
                console.log("Return value:" + result);
      </script>
   </body>
</html>

这个示例通过 RegExp 对象指定两种模式,然后为这两种模式调用 toString 方法。列表 5-16 的输出如图 5-16 所示。

A394309_1_En_5_Fig16_HTML.jpg

图 5-16。输出
注意

exec 和 test 方法在某种程度上是相似的,都将要搜索的字符串作为输入。不同之处在于,exec 返回匹配的子字符串或空值,而 test 方法返回 true 或 false。

摘要

本章向您介绍了正则表达式,包括如何将正则表达式与字符串方法结合使用。您还了解了 RegExp 对象的属性和方法,以及代码示例。

第六章讨论了 JavaScript 中的另一个重要话题:函数。

六、函数

本章向您介绍函数的基础知识以及它们提供的优势。首先,您将看到 JavaScript 中用于创建函数的不同类型的方法。然后,您将看到如何定义向调用程序返回值的函数,以及如何为定义的函数指定参数(自变量)。

函数:概述

函数可以简单地定义为一组语句或子程序,可以在 JS 程序中的任何地方使用或调用。一个函数通常有一个名字,但不一定要有名字,在这种情况下,它被称为一个匿名函数。一个函数可以有零个或多个参数。

一个函数有一个用花括号括起来的函数体,函数体可以包含几个语句。函数还可以包括 return 语句,该语句是可选的,可用于向调用方代码返回计算值。(在本章的后面,你会学到更多关于 return 语句的知识。)函数的处理在 return 语句处停止。

使用函数为开发人员提供了以下优势:

  • 它节省了大量的时间和精力,因为开发人员不需要为特定的需求重写代码。

  • 程序的代码比没有函数时更紧凑,更有组织,也更容易理解。

  • 函数一旦被定义,就可以在整个程序或其他函数中使用。

要在 JavaScript 中定义函数,可以使用 function 关键字,后跟唯一的函数名、参数列表和花括号中的代码块。函数的语法是

function name(parameter-list)
      {
         statements
      }

这里,name 是函数名,parameter-list 表示要传递给函数的参数列表,语句包括函数体,可能包括也可能不包括对其他函数的调用。

如果函数没有参数,您仍然需要在函数名后面加上括号:

function name()
      {
         statements
      }

为了简单起见,本章只显示有名字的函数。

清单 6-1 中的例子展示了命名函数以及如何从函数中返回值。

清单 6-1。函数示例
function triple(num){
    return ( 3  * num );
}

这个简单的例子将数字 num 增加了三倍。函数的名称是 triple,num 是要计算其三重值的参数。然后返回计算出的值。

此函数可用于 console.log 方法或如下所示的警报函数中:

alert( 'Tripled figure is '+ triple(2));

该代码的输出如图 6-1 所示。

A394309_1_En_6_Fig1_HTML.jpg

图 6-1。输出

如前所述,要正确调用函数,需要使用 function()操作符。省略运算符()会导致返回函数(定义)的代码。考虑图 6-2 所示的例子。

A394309_1_En_6_Fig2_HTML.jpg

图 6-2。输出
清单 6-2。省略函数运算符示例
alert( 'Tripled figure is '+ triple);

列表 6-2 的输出如图 6-2 所示。

声明函数

既然您已经熟悉了 JS 中函数的基础知识,本节将描述一些在程序中创建函数的方法。函数主要可以通过两种方式创建:

  • 使用函数表达式

  • 使用函数声明

以下小节详细介绍了每一种方法及其进一步的分类。

使用函数表达式

此选项涉及在更大的表达式中定义函数。通过函数表达式定义的函数可以是以下三种类型中的任何一种:

  • 自调用函数

  • 命名函数表达式

  • 匿名函数表达式

自调用函数

自调用函数是可以用名称或不用名称来定义但被自动调用的函数。不涉及声明和调用。表达式自动执行函数。

自调用函数的语法如下所示:

(function(){
// code
})();

同样,函数名后跟括号()是绝对必要的。

清单 6-3 展示了一个自调用函数的工作示例。

清单 6-3。自调用函数示例
(function () {
    console.log("See you all!");
})();

此示例声明了不带名称的函数。该函数是自调用的,并在浏览器控制台显示输出,如图 6-3 所示。

A394309_1_En_6_Fig3_HTML.jpg

图 6-3。输出

命名函数表达式

顾名思义,命名函数是用函数表达式中的名称来声明的。

命名函数的语法是

var myFunction = function namedFunction(){
    statements
}

这里,定义了一个变量 myFunction,函数对象被分配给它。然后,您可以使用变量 myFunction 并提供与该函数相关的任何值(如果适用),以便执行该函数的代码。

考虑清单 6-4 中的例子,它将函数名声明为 myFunction,并将它赋给声明的变量 myValue。

清单 6-4。命名函数示例
var myValue = function myFunction() {
         return 'Hello';
    }
console.log("Text displayed as : " +myValue());

清单 6-4 的输出如图 6-4 所示。

A394309_1_En_6_Fig4_HTML.jpg

图 6-4。输出

匿名函数

没有名字的函数(表达式)称为匿名函数。匿名函数的语法是

var myFunction = function() {
    statements
}

清单 6-5 展示了一个匿名函数的例子。

清单 6-5。匿名函数示例
var myFunction = function()
    {
         return 'Hello';
    }
console.log("Text displayed as : " +myFunction());

此示例将所讨论的函数表达式的结果赋给变量 myFunction,并使用 myFunction 调用它。

列表 6-5 的输出如图 6-5 所示。

A394309_1_En_6_Fig5_HTML.jpg

图 6-5。输出

使用函数声明

函数声明定义一个有名字的函数,不涉及任何变量赋值。声明的函数只在被调用时执行,不会立即执行。

函数声明的语法是

function funct_name(parameters) {
    Statements
}

清单 6-6 展示了一个函数声明的例子。

清单 6-6。函数声明示例
function myFunction()
    {
         return 'Hello';
    }
console.log("Text displayed as : " +myFunction());

在示例中,myFunction()是声明的函数,在 console.log 函数中调用。每当在程序中调用它时,它都返回值“Hello”。

注意

函数声明不是可执行语句。函数声明的末尾没有必要有分号。

列表 6-6 的输出如图 6-6 所示。

A394309_1_En_6_Fig6_HTML.jpg

图 6-6。输出
注意

除了函数表达式和函数声明之外,还有一种函数构造器创建函数的方式。在这种方法中,使用了 new 关键字。构造函数()将代码视为存储在字符串中。这方面的一个例子如下所示:

var average = new Function('a', 'b', 'return ((a + b) / 2)' );

这里,参数用引号括起来,并用逗号分隔(在本例中是 a 和 b)。第三个字符串是代码。这种方法速度慢且难以调试,因此不推荐使用。

最好使用函数表达式或函数声明。

函数声明和函数表达式的概要比较

这是一个宣言:

function product(a, b) {
    return a * b;
}

这是一个表达式:

var product = function (a, b) {
    return a * b;
};

函数参数和自变量

正如本章前面提到的,函数可能包含也可能不包含参数。给定函数可能有一个或多个参数。

根据提供给函数的参数值,函数的行为会发生变化,结果也会相应地进行计算。像 a 和 b 这样的参数可以像函数代码中的任何局部变量一样进行寻址。这些参数在括号中指定,用逗号分隔。

在以下示例中,p1 和 p2 是参数:

function anexample(p1, p2) {
    ...
}

在函数调用时,为参数提供的相应值被称为参数。在下面的示例中,10 和 11 是参数:

anexample(10,11);

清单 6-7 中的一个例子。

清单 6-7。函数参数示例
<!DOCTYPE html>
<html>
   <body>
      <script>
         function mymessage(user) {
         console.log("Good to see you " + user);
         }
         mymessage("Diego Dora")
      </script>
   </body>
</html>

在这段代码中,函数 mymessage 在声明时使用了一个参数 user。它接受一串文本作为参数。接下来,调用函数 mymessage 并传递文本“Diego Dora”。

清单 6-7 的输出如图 6-7 所示。

A394309_1_En_6_Fig7_HTML.jpg

图 6-7。输出

缺少参数和未定义的值

可以调用多参数函数并省略一些参数。在函数中,任何缺少的参数的值都被设置为未定义。提供的任何额外参数都会被忽略。

考虑清单 6-8 中的代码。

清单 6-8。缺少参数示例
function myFunction(firstparam, secondparam) {
    if (secondparam === undefined) {
        console.log(secondparam)
    }
}
myFunction(1);

清单 6-8 是一个涉及缺失参数的例子。函数 myFunction 有两个参数,firstparam 和 secondparam。在代码中,if 语句检查是否提供了 secondparam 的值,并根据未定义的值进行检查。然后调用该函数,并且只传递一个参数。在这种情况下,因为 secondparam 的值尚未设置,所以该函数检查 if 条件并显示 undefined。

列表 6-8 的输出如图 6-8 所示。

A394309_1_En_6_Fig8_HTML.jpg

图 6-8。输出

参数数组

函数可能包含一个名为 arguments 的特殊数组,该数组包含通过函数调用提供的所有参数。即使函数定义中没有定义参数,该数组也包含一个值。清单 6-9 展示了一个演示参数数组的例子。

清单 6-9。参数数组示例
function myFunction() {
           console.log(arguments[0]);
           console.log(arguments[1]);
           console.log('Total Parameters passed are ' + arguments.length) }
myFunction('Diego Dora' , 'Jon Reed');

此示例中的函数 myFunction 在声明中没有指定任何参数。在函数中,显示了数组参数的第一个和第二个元素,以及数组的总长度。然后,该示例调用函数并提供两个参数。代码不会产生任何错误。

清单 6-9 的输出如图 6-9 所示。

A394309_1_En_6_Fig9_HTML.jpg

图 6-9。输出

模拟可选参数传递

也可以在函数中选择参数。清单 6-10 展示了它是如何工作的。

清单 6-10。可选参数示例
function myDivision(number, divisor) {
  if (divisor === undefined)
  {
      return('Division by zero not possible');
  }
   else

      return  number / divisor;
  }
console.log(myDivision(8));
console.log(myDivision(100, 10));

这个例子展示了数的除法。函数 myDivision 既可以用两个参数调用,也可以用一个参数调用。由于在第一次函数调用中没有提供除数,为了避免被零除,将检查除数的值,并显示相应的消息。当第二次调用同一个函数 myDivision 时,数字和除数分别作为 100 和 10 传递。这一次执行除法并输出值。

清单 6-10 的输出如图 6-10 所示。

A394309_1_En_6_Fig10_HTML.jpg

图 6-10。输出

返回语句

当/如果您希望从函数返回值时,return 语句是必需的,也就是说,它将计算值返回给函数调用方。return 语句应该是函数中的最后一条语句,因为一旦遇到 return 语句,执行就会停止。

清单 6-11 展示了一个返回语句如何在除法运算中工作的例子。

清单 6-11。return 语句示例
<html>
<body>
<script>
         var result = function(number, divisor)
         {
           return number / divisor;
         };
        console.log(result(150, 10))
</script>
</body>
</html>

所示函数有两个参数,数字和除数。return 语句用于将值返回给调用者。在执行时,当到达 return 语句时,会立即将控制权以及计算出的值交给调用方。

列表 6-11 的输出如图 6-11 所示。

A394309_1_En_6_Fig11_HTML.jpg

图 6-11。输出

函数调用

如前所述,一个函数调用另一个函数也是可能的。为了更好地理解,考虑清单 6-12 中的例子。

清单 6-12。函数调用其他函数示例
<!DOCTYPE html>
<html>
   <body>
      <script>
         function total1(a, b) {
                return a + b;
         }
         function  average(a, b) {

                 var av = total1(a, b) / 2;

                 console.log("Average = " + av);
         }
        average(8, 8);
      </script>
   </body>
</html>

此示例计算两个数字的平均值。它声明了两个函数 total1 和 average,这两个函数都有两个参数 a 和 b。total 1 函数返回这两个数字的总和。在 average 函数中,首先调用 total1 函数来计算这两个数字的总和,然后将这个总和除以 2 来计算平均值。console.log 函数用于显示平均值。调用 average 函数时使用了值 8 和 8。

列表 6-12 的输出如图 6-12 所示。

A394309_1_En_6_Fig12_HTML.jpg

图 6-12。输出

参数按值传递还是按引用传递?

在 JavaScript 中,不能通过引用传递参数。当您将一个变量传递给一个函数时,JS 会复制该参数并对其进行处理。因此,在函数中,传递的参数值不能改变。

为了更好地理解为什么不能通过引用传递参数,请考虑清单 6-13 中的例子。

清单 6-13。通过引用传递尝试示例
function decNumber(countVal) {
    countVal--;
}
var i = 10;
decNumber(i);
console.log("Value after attempt is : " + i);

该示例显示了使用函数 decNumber 更改变量 I 的值的尝试。它声明函数 decNumber 并传递 countVal。即使在调用函数 decNumber 之后,变量 I 的值也不会改变。

输出列表 6-13 如图 6-13 所示。

A394309_1_En_6_Fig13_HTML.jpg

图 6-13。输出

JS 对传递给函数的值进行更改的一种间接方式是通过使用数组。清单 6-14 中显示了修改后的相同示例。

清单 6-14。按值传递函数示例
function decNumber(countVal) {
    countVal[0]--;
}
var i = [10];
decNumber(i);
console.log("Value decremented to : " + i[0]);

该示例显示了如何使用函数 decNumber()递减数组元素的值。它声明了一个数组 I,其元素 0 被赋予了要被改变的值。该数组作为参数传递给函数。在函数代码中,数组的第 0 个元素减 1。在执行函数时,该值被改变并显示。

列表 6-14 的输出如图 6-14 所示。

A394309_1_En_6_Fig14_HTML.jpg

图 6-14。输出

函数命名

总结这一章的 JavaScript 函数,需要注意的是:不要用函数名来命名函数。这是严格不允许的。考虑以下代码:

function function(countVal) {
    countVal--;
}

在这种情况下,出现图 6-15 所示的错误。

A394309_1_En_6_Fig15_HTML.jpg

图 6-15。错误

摘要

在这一章中,你首先探索了函数的基础,并看到了它们的优点。然后,您看到了函数是如何声明的。有了这些重要的基础知识,第七章将讨论 JavaScript 中的高级函数。

七、利用函数做更多事情

第六章向你介绍了函数的基础知识,以及它们如何使复杂的数学代码变得容易执行。您了解了函数是如何创建的,以及每次调用它们时它们是如何执行任务的。您还看到了使用函数、参数和实参的不同方式。本章涵盖了与函数相关的更高级的主题。您将看到提升如何应用于函数,并了解为什么函数被称为“一等公民”您还将学习如何声明嵌套函数,如何对函数应用闭包,以及如何声明递归函数。

功能环境中的提升

如第一章所述,变量提升是指在变量被实际声明之前使用它。在函数的上下文中也完全支持提升。这意味着您甚至可以在声明函数之前调用它。

考虑清单 7-1 中函数提升的例子。

清单 7-1。功能提升
<html>
 <body>
  <script>
   say_hello_to_user();

   function say_hello_to_user(){
      alert('Hello how are you, today?');
    }
  </script>
</body>
</html>

这段代码运行良好,不会产生任何语法错误。脚本中的第一行是对 say_hello_to_user 函数的调用。这个函数的声明实际上在后面。JavaScript 将函数的声明移动到作用域的开始。这相当于清单 7-2 中所示的例子。

清单 7-2。等效 JS 代码
<script>

 function say_hello_to_user(){
    alert('Hello how are you, today?');
  }
 say_hello_to_user();
</script>

两个清单的输出如图 7-1 所示。

A394309_1_En_7_Fig1_HTML.jpg

图 7-1。程序输出
注意

变量声明没有完全提升。

值得注意的是,如果函数体或函数代码之前的代码中有任何语法错误,将首先检查函数体的语法,并突出显示任何语法错误。如图 7-2 所示。

A394309_1_En_7_Fig2_HTML.jpg

图 7-2。功能代码中的语法错误

试图将变量声明与函数表达式一起使用会导致语法错误。考虑清单 7-3 中所示的例子。

清单 7-3。错误代码示例
<script>

hello();
var hello   = function say_hello_to_user(){
    alert('Hello how are you, today?');
  }

</script>

这段代码产生了一个语法错误,如图 7-3 所示。

A394309_1_En_7_Fig3_HTML.jpg

图 7-3。语法错误

考虑清单 7-4 中错误代码的另一个例子。

清单 7-4。第二个不正确的代码示例
<script>

var hello;
hello();
hello   = function say_hello_to_user(){
    alert('Hello how are you, today?');
  }

</script>

这个程序也会产生一个语法错误。在这里我们尝试一个变量 hello。JS 不接受将变量 hello 用作函数的尝试,语法错误导致程序如图 7-4 所示。

A394309_1_En_7_Fig4_HTML.jpg

图 7-4。语法错误

一等公民

在 JavaScript 中,函数被视为一等公民。他们可能是

  • 赋给变量

  • 作为参数传递给函数

  • 函数的返回值

为了便于比较,清单 7-5 展示了一个简单的函数示例。

清单 7-5。简单函数示例
<!DOCTYPE html>
<html>
   <body>
      <script>
         var myMessage = function()
         {
         console.log("Good To See You....!");
        };
      myMessage();
      </script>
   </body>
</html>

在这个简单的函数示例中,myMessage 没有列出任何参数名(即函数为空)。要在脚本中调用该函数,只需编写该函数的名称,如代码所示。这将调用消息并显示消息。

列表 7-5 的输出如图 7-5 所示。

A394309_1_En_7_Fig5_HTML.jpg

图 7-5。输出

清单 7-6 展示了如何将一个函数作为输入传递给另一个函数并从函数本身返回。

清单 7-6。一等公民的例子
<html>
<body>
<script>

var function1 = function() {
  console.log("Function 1 Called");
};

var function2 = function(input) {
  return input;
};

function2(function1)();

</script>
</body>
</html>

这里,该函数输出在浏览器控制台中调用的函数 1。该函数通过赋值被赋给变量 function1。接下来,另一个匿名函数将名为 input 的参数作为输入,并返回它。该功能被分配给变量 function2。最后,调用 function2 并将 function1 作为参数传递。因为 function2 将传递给它的任何值作为返回值返回,所以下面两个表达式是相等的:

  • 功能 2(功能 1)

  • 功能 1

要调用 function1,您必须包括括号(),如图所示。否则,会导致语法错误。程序的输出如图 7-6 所示。

A394309_1_En_7_Fig6_HTML.jpg

图 7-6。程序输出

嵌套函数

嵌套函数也称为内部函数,是在另一个函数中定义的函数。包含内部函数的函数称为外部函数。内部函数可能有也可能没有 return 语句。每次调用外部函数时,都会创建嵌套函数的一个实例。

考虑清单 7-7 中的嵌套函数的例子。

清单 7-7。嵌套函数示例
<html>
 <body>
  <script>

     function myfunction(d1, d2) {
       function doDivision(d1, d2) {
           return d1 / d2;
       }

     return doDivision(d1, d2);
     }

    var div = myfunction(4, 2);
    console.log(div);
 </script>
</body>
</html>

这个例子展示了两个数的除法。外部的主函数名为 myfunction,内部定义了 doDivision 函数。这个内部函数是通过提供值 4 和 2 来调用的,它的值存储在变量 div 中,稍后会显示在浏览器控制台中。在调用外部函数 myfunction 时,会创建内部函数 doDivision 的一个实例。

还要注意,参数 d1 和 d2 是为两个函数指定的。这在 JavaScript 中是允许的,不会导致任何问题。程序的输出如图 7-7 所示。

A394309_1_En_7_Fig7_HTML.jpg

图 7-7。程序输出

当处理嵌套函数时,重要的是要注意内部函数可以访问主外部函数的范围。换句话说,函数 doDivision 可以使用外部函数 myfunction 的参数和变量。在清单 7-7 中,myfunction 的 d1 和 d2 参数分别作为参数 d1 和 d2 提供给内部函数 doDivision。这是不必要的,因为 doDivision 可能会访问外部函数 myfunction 的 d1 和 d2。清单 7-8 展示了清单 7-7 中的代码是如何通过依赖 doDivision 可以访问 myfunction 的 d1 和 d2 来简化的。

清单 7-8。第二个嵌套函数示例
<html>
 <body>
  <script>
     function myfunction(d1, d2) {
       function doDivision() {
           return d1 / d2;
       }
       return doDivision();
     }
    var div = myfunction(4, 2);
    console.log(div);
  </script>
</body>
</html>

这是嵌套 division 示例的更好形式,因为它从 doDivision 函数中删除了多余的参数。在 doDivision 主体内部,清单 7-8 返回 d1 / d2 的除法值(参数 d1 和 d2 提供给 myfunction)。

该程序的输出如图 7-8 所示,与之前显示的输出相同。

A394309_1_En_7_Fig8_HTML.jpg

图 7-8。程序输出

也可以匿名声明嵌套函数。清单 7-9 中显示的例子试图解决前面两个清单中相同的除法问题,但是方式有点不同,也更复杂。

清单 7-9。匿名嵌套函数示例
<html>
<body>
<script>
            function doDivision(d2) {
             return function(d1) {
             return d1/d2;
             };
           }

           var div = doDivision(2);
           console.log(div(6));
</script>
</body>
</html>

在这种形式的嵌套函数中,return 语句使用了两次。内部函数使用外部函数的参数 d2。此外,内部函数返回对一个函数的引用,该函数将被除的数作为输入。第一个返回语句用于调用 d1 的其他函数,第二个返回语句返回 d1/d2 除法的结果。

清单 7-9 的输出如图 7-9 所示。

A394309_1_En_7_Fig9_HTML.jpg

图 7-9。程序输出

让我们看看嵌套函数的另一种形式。也可以在外部函数本身的代码体中调用内部函数(在外部函数中声明)。考虑清单 7-10 中的例子。

清单 7-10。调用内部函数
function myFunction() {
  var mytext = "Mytext";

  function showtext() {
       console.log(mytext);
  }
       showtext();
}
myFunction();

这里,外部函数和内部函数分别是 myFunction 和 showtext。变量 mytext 在 myFunction 中定义。内部函数 showtext 是在 myFunction 中声明的。然后调用 showtext 函数。当调用函数 myFunction 时,控制台的输出如图 7-10 所示。

A394309_1_En_7_Fig10_HTML.jpg

图 7-10。程序输出

词法范围

在函数的上下文中,词法范围意味着变量的范围是由变量在 JavaScript 源代码中的位置决定的。在函数外部声明的任何变量对于整个 JS 程序都是可访问和可见的(即全局变量)。另一方面,在给定函数中声明的变量只对该函数的代码块可见和可访问。这就是所谓的功能范围。在嵌套函数的情况下,内部函数可以访问外部函数中声明的变量。在内部函数中声明的任何变量都不能在外部访问。

考虑清单 7-11 中词法范围的例子。

清单 7-11。词法范围示例
function myFunction() {
  var mytext = "Mytext";

  function showtext() {
       console.log(mytext);
  }
       showtext();
}

函数 myFunction 声明了一个局部变量 mytext 和一个函数 show text——在 myFunction()内部定义的内部函数,该函数仅在 myFunction 的主体中可用。这里,showtext 没有局部变量,但是它可以访问它的外部函数,在本例中是 myFunction。在 myFunction 主体中,调用 showtext 函数以显示变量 mytext 中包含的文本。

让我们考虑清单 7-12 中词法范围的另一个例子。

清单 7-12。第二个词法范围示例
<html>
<body>
<script>
     var function1  = function(){
     var text1 = "Text1";
     function f2() {
             if(true){
                var text2  = "Text 2";
                console.log(text2);
              }

              if(true){
                console.log(text2);
              }
     }
     f2();
     console.log(text2) ; // gives error – ERROR
}
function1();

</script>
</body>
</html>

在这个例子中,变量 function1 被分配给一个函数。在这个(外部)函数中有一个变量 text1 和一个内部函数 f2。在内部函数中有两个 if 语句和两个块(显示在花括号中)。

变量 text2 在函数 f2 中的任何地方都是可访问的,与声明它的代码块无关。然而,text2 在函数 f2 之外是不可访问的。因此,最后一条 console.log 语句会导致错误。通过外部函数可以访问 text1 变量。

关闭

在正常情况下,函数中的局部变量只在函数执行期间存在。函数执行后,通常不能访问局部变量。然而,通过使用 closure,在函数执行之后,可以保持局部变量。

在 JavaScript 中,您可以创建被称为闭包的特殊函数,这些函数会记住创建它们的环境(状态)。这些包括函数中的独立局部变量。所以,换句话说,一个闭包由

  • 一项功能

  • 函数的环境

环境在这个上下文中是指闭包创建时的局部变量。考虑清单 7-13 中产生语法错误的非闭包例子。

清单 7-13。句法误差
function myFunction() {
   var num = 10;
  }
 console.log(num);

这将产生一个语法错误,因为 num 对于外部世界是不可访问的。但是,通过使用闭包,可以访问 num。考虑清单 7-14 中的例子。

清单 7-14。关闭示例
function Func() {
  var num = 10;
  function returnnumber() {
    return num;
  }
  return returnnumber;
}

var closure1 = Func();
console.log(closure1());

执行该代码时,输出如图 7-11 所示。

A394309_1_En_7_Fig11_HTML.jpg

图 7-11。程序输出

该号码将显示在浏览器的控制台中。内部 returnnumber 函数在执行前从外部函数 Func 返回。Func 已经成为一个封闭。在这种情况下,Func 是一个闭包,它包含函数和在闭包创建时就存在的 num 值 10。

清单 7-15 展示了一个更有用的例子。

清单 7-15。使用闭包的除法
<html>
<body>
<script>

function divisionfactory(divisor) {
  return function performdivision(number) {
    return number / divisor ;
  }
}

var divideby10 = divisionfactory(10);
var divideby20 = divisionfactory(20);

console.log(divideby10(100));
console.log(divideby20(200));

</script>
</body>
</html>

此示例定义了一个函数 divisionfactory,它将参数除数作为输入,并返回对另一个函数的引用。内部函数被称为 performdivision(尽管您也可以将其命名为匿名)。内部函数只有一个参数 number,并返回除数/除数的结果。顾名思义,外部函数 divisionfactory 用于创建将输入的数字除以特定值的函数。

出于示例的目的,清单 7-15 创建了两个函数,divideby10 和 divideby20,分别将它们的参数除以 10 和 20。这两个新函数是具有相似主体但独立环境的闭包。对于 divideby20,除数的值是 10,而对于 divideby10,除法的值是 20。

列表 7-15 的输出如图 7-12 所示。

A394309_1_En_7_Fig12_HTML.jpg

图 7-12。除法输出

考虑清单 7-16 中另一个有趣的闭包例子。

清单 7-16。另一个闭包例子
var add_element = (function() {
    var total_elements = 0;
    var array = [];
    return function addition(element) {
              array[total_elements] = element;
              console.log(array);
              total_elements = total_elements + 1;

 }
})();

add_element(10);
add_element(11);
add_element(12);

这个例子定义了一个函数,并把它赋给变量 add_element。在代码中,变量 total_elements 和 array 分别用初始值 0 和[ ]声明。属性元素被分配到数组的末尾。此外,每向数组中插入一个元素,total_elements 计数器就加 1。此函数返回一个函数加法,将传递给它的新元素添加到数组中,并增加数组中元素的计数。

清单 7-16 中的例子调用 add_element 三次,分别提供值 10、11 和 12。列表 7-16 的输出如图 7-13 所示。

A394309_1_En_7_Fig13_HTML.jpg

图 7-13。显示数组元素的程序输出

add_element 是一个包含函数加法的闭包。但是,因为清单 7-16 使用了自调用函数,所以初始化语句(将 array 设置为[]并将 total_elements 设置为 0)只执行一次。正如您将看到的,每个函数闭包都记得它被创建时的状态。其中包括变量 array 和 total_elements。

递归函数

正如在第六章中已经提到的,一个函数有可能调用它自己——也就是说,一个根据它自己定义的函数。这样的函数被称为递归函数。使用递归可以解决的典型问题包括斐波那契数列问题和著名的汉诺塔问题。递归为开发人员提供了一些优势,比如开发简洁代码的能力,同时也有助于开发人员避免循环。

定义递归函数时,指定一个终止条件是很重要的。如果没有指定这样的条件,可能会发生无限的“函数”调用。在通常情况下,递归函数被声明为命名函数。但是,也可以将匿名函数定义为递归函数。

现在让我们来看一个 JavaScript 中递归函数的完整工作示例。假设我们需要输入一个数字,然后分别拼写每个数字。例如,如果数字 647 作为输入传递,那么数字 6、4 和 7 必须以正确的顺序分别显示。

清单 7-17 中显示了与该示例相关的代码。

清单 7-17。递归示例
<html>
<body>
<script>
 function spell_number( num ) {
            if ( num < 10 ) {
               console.log(num);
             }
            else {
               spell_number( Math.floor(num / 10) ) ;
               console.log( num % 10 );
        }
   }
 spell_number(647);
</script>
</body>
</html>

给定问题的基本解决方案是,要按数字拼写的数字是

  • 数字本身,如果数字小于 10

  • 商的拼写位数(通过除以 10 获得),后跟数字除以 10 的余数

清单 7-17 声明了一个名为 spell_number 的函数,它将参数 num 作为输入。在代码中,该函数检查提供的数字是否小于 10。终止条件是当作为输入传递的数字小于 10 时。在这种情况下,函数应该返回数字本身,而不是调用递归函数。数字直接输出到控制台,不递归调用 spell_number。

如果数字大于或等于 10,清单 7-17 递归调用函数并提供 num 除以 10 的商。接下来,num 除以 10 的余数在控制台中输出。因为我们需要按照从左到右的正确顺序打印数字,所以我们首先调用递归函数,然后打印余数。

对于输入的数字 647,函数 spell_number 的调用顺序如下所示:

  • 函数 spell_number(647)用输入 647 调用的函数

  • 函数 spell_number(64) //用输入 64 调用的函数

  • 函数 spell_number(6)用输入 6 调用的函数

程序的输出如图 7-14 所示。

A394309_1_En_7_Fig14_HTML.jpg

图 7-14。程序输出

也可以使用匿名函数和变量表达式重写相同的问题。清单 7-18 显示了如何实现这一点。

清单 7-18。匿名递归函数
<html>
<body>
<script>
  var spell_number = function( num ) {
            if ( num < 10 ) {
               console.log(num);
             }
            else {
               spell_number( Math.floor( num / 10) ) ;
               console.log( num % 10 );
        }
   }
 spell_number(647);

</script>
</body>
</html>

如您所见,大部分代码与清单 7-17 中的相同。唯一的区别是清单 7-18 定义了没有名字的函数,并指定了一个变量 spell_number,函数声明被赋给这个变量。对递归函数的调用是通过变量 spell_number 完成的。程序的输出是一样的。

摘要

在本章中,您首先看到了提升是如何应用于函数的,然后您发现了为什么函数被称为一等公民。您还了解了如何声明嵌套函数,以及闭包的含义。最后,您学习了如何声明递归函数。

第八章将向你展示如何在 JS 中实现面向对象。

八、JavaScript 中的面向对象编程

和 ABAP 一样,JavaScript 允许你创建对象。然而,这两种语言中关于对象创建的概念是不一样的。本章涵盖了 JS 中的对象创建、实例化和继承。从面向对象编程(OOP)的概述开始,本章的其余部分展示了 OOP 是如何在 JS 中实现的,以及相关的语法。它详细介绍了 this 操作符,然后介绍了创建对象的各种方法,接着是使用 new 关键字的实例化步骤。一旦你对对象有了一个基本的理解,这一章就转移到使用原型在 JS 中实现的继承。本章介绍了对象和子对象的真实例子,以及用 JavaScript 实现它们的示例代码清单。

为了简洁起见,本章只展示了 JS 代码。到目前为止,您已经完全意识到这段代码需要 HTML 标记才能在浏览器中执行。

一般面向对象编程

要理解 JavaScript 中的面向对象编程,您需要从总体上理解面向对象编程。

在 OOP 中,你使用对象的概念来模拟程序中真实的对象。概念对象可能包含与您已经建模的真实对象相关的数据和代码,或者开发人员希望对象展示的特性(行为)。例如,你可以有一个 Player 类,它包含许多属性(attributes)和一个函数 sayhello()方法,如图 8-1 所示。

A394309_1_En_8_Fig1_HTML.jpg

图 8-1。职业选手

这个对象表示被称为一个。(然而,在 JS 中,使用了一种不同的机制,稍后将对此进行描述。)一个类可以被认为是一个模板,它指定了源自它的对象必须具有的属性。

您可以创建一个类的多个实例。这些对象包括类定义中指定的数据和特征。例如,对于 Player 类,可以创建任意数量的玩家,如图 8-2 所示。创建对象时,执行类的构造函数以创建新的对象实例。这被称为实例化

A394309_1_En_8_Fig2_HTML.jpg

图 8-2。玩家的实例

图 8-2 中显示的 Player 类有两个实例,player1 和 player2,每个都有自己的 player_name、weight 和 height 属性,以及 sayhello()方法中不同的文本字符串。

进一步看这个例子,假设你不想允许创建普通玩家,这意味着没有人可以只是一个“玩家”每个人必须选择成为一个特定类型的球员,如板球运动员或足球运动员。在 OOP 领域中,可以从现有的类中创建新的类。被称为子类的新类然后可以继承驻留在它们的父类(即,从其继承的类)中的数据和代码。这允许重用父类中的现有功能(包括其子类之间共有的数据和代码),而不是在许多单独的类中复制该功能。如果需要,您还可以向派生的子类添加额外的功能。

为了更好地理解继承的概念,考虑图 8-3 所示的例子。

A394309_1_En_8_Fig3_HTML.jpg

图 8-3。板球运动员和足球运动员儿童班

Cricket Player 和 Football Player 类有许多共同的属性,例如 player_name、weight 和 age,因此在父类 Player 中定义所有这些属性并创建 Cricket Player 和 Football Player 作为继承这些属性的子类更容易。

也可以在这些类中不同地指定给定的特性。例如,板球运动员子类的 sayhello()文本可能是“我是板球运动员”,而足球运动员子类的 sayhello()文本可能是“我是足球运动员”。在不同的对象类型中不同地实现相同特性的能力被称为多态性

现在可以从这些子类创建实例,如 CricketPlayer1、CricketPlayer2、FootballPlayer1 等。

对象实例和构造函数

JavaScript 不是典型的面向对象编程语言。其他的 OOP 语言有一个 class 语句(定义)来定义类。使用这些类,可以创建包含类中包含的属性和方法的对象。相比之下,JS 使用称为构造函数的特殊函数来定义对象属性和方法。一个构造函数可以用来创建任意数量的对象,并可以选择添加额外的函数和数据。

如果使用构造函数创建一个新的实例,构造函数中可用的特性通过原型链链接起来。(这与其他 OOP 语言不同,在其他 OOP 语言中,所有功能都是从类中复制到新的实例化对象中。)

本节将向您展示在 JS 中模拟对象创建的四种不同方法(使用 Player 对象作为真实的例子):

  • 使用对象文字

  • 使用构造函数

  • 使用 Object()构造函数

  • 使用 create()方法

方法 1:使用 O 对象文字

第一种方法是使用一个使用对象文字的函数。清单 8-1 中显示了一个处理播放器示例的函数。

清单 8-1。使用对象文字
function defineaPlayer(pname,weight, height) {
  var myobj = {};
  myobj.name = pname;
  myobj.weight = weight;
  myobj.height = height;
  myobj.sayhello = function() {
    alert('Hi, my name is ' + this.pname + '.');
  };
  return myobj;
}

这里,函数 myPlayer 将 pname、weight 和 height 作为输入。在 myPlayer 函数中定义了一个对象 myobj,然后添加了名称、重量和高度等属性。清单 8-1 还定义了一个 sayhello 方法。最后,该函数返回 myobj 对象。

然后,您可以通过调用此函数来创建新的播放器:

var player =  defineaPlayer('James Watson', 100,50);
console.log(player.pname);
console.log(player.sayhello());

虽然这种安排是可行的,但是它很冗长,而且不必要地声明一个空对象并返回它。

方法 2:使用构造函数

JavaScript 提供了另一种使用构造函数创建对象的简单方法。您可以为播放器示例定义一个构造函数,如清单 8-2 所示。

清单 8-2。播放器构造函数
function Player(pname,weight, height) {
  this.name = pname;
  this.weight = weight;
  this.height = height;
  this.sayhello = function() {
    alert('Hi, my name is ' + this.pname + '.');
  };
注意

JavaScript 中的构造函数类似于其他 OOP 语言中的类(保留字类)。

构造函数定义了与对象相关的方法和属性。this 关键字用于为正在创建的对象的属性赋值。方法 1(使用 oobjectliteral)和方法 2 的主要区别在于后者使用了 this 关键字。这意味着每当使用构造函数创建对象时,所标识的各种属性将等于通过构造函数调用传递的相应参数。

考虑以下示例:

var player1 = new Player('James', 100, 20);
var player2 = new Player('John', 120, 60);

下面的语句将会起作用:

player1.pname
player2.pname

这个例子创建了两个对象,玩家 1 和玩家 2。它们有属性 pname 和方法 sayhello,但是它们是分开存储的,不会相互冲突。在每种情况下,new 关键字用于创建一个新的对象实例,后跟括号中的各种参数。每个对象实例都是使用 Player 创建的,如清单 8-3 所示。

清单 8-3。玩家示例
function Player(pname,weight, height) {
  this.name = pname;
  this.weight = weight;
  this.height = height;
  this.sayhello = function() {
    alert('Hi, my name is ' + this.pname + '.');
  };
}

创建新对象后,player1 和 player2(实际效果)包含以下内容:

{
  name : James;
  weight : 100;
  height : 20;
  sayhello : function() {
    alert('Hi, my name is ' + this.pname + '.');
  };
}

{
  name : John;
  weight : 120;
  height : 60;
  sayhello : function() {
    alert('Hi, my name is ' + this.pname + '.');
  };
}

方法 3:使用 Object()构造函数

创建对象的第三种方法是使用 Object()构造函数。考虑以下代码:

var player1  = new Object();

这有一个在 player1 变量下创建的空对象。完成后,您可以向对象添加方法和属性。为此,您可以使用括号或点号,如下所示:

player1.pname = 'John';
player1.weight = 100;
player1['height'] = 30;
player1.sayhello = function() {
 alert('My name is ' + this.pname) ;
};

也可以在调用 Object()构造函数时传递文本,并指定属性和方法。这更加简洁易懂,如清单 8-4 所示。

清单 8-4。使用 Object()构造函数
var player1 = new Object({
  pname: 'John',
  height: 100,
  weight: 20,
  sayhello: function() {
    alert('My name is' + this.pname + '.');
  }
});

player1.sayhello();

如您所见,清单 8-4 中的一条语句调用 Object()构造函数并指定属性和方法的值。该语句与前面的代码块具有相同的效果。代码的输出如图 8-4 所示。

A394309_1_En_8_Fig4_HTML.jpg

图 8-4。使用 Object()构造函数的程序输出

方法 4:使用 create()方法

JS 语言有一个名为 create()的方法,允许您从现有对象创建对象实例。此处显示了一个代码示例:

var player2 = Object.create(player1);

这里,现有对象是 player1。Object 的 create 方法用于创建一个完全相同的对象 player2(即,它具有 player1 中可用的相同属性和方法)。一旦执行了前面的语句,如果用于 player1,下面的语句将起作用并提供相同的输出:

console.log(player2.pname);
player2.sayhello();

这种方法非常有用,使开发人员能够基于另一个实例创建新的实例。

JavaScript:一种基于原型的语言

正如本章前面提到的,在传统的 OOP 中,类是被定义的。当从类实例化对象时,驻留在类中的属性和方法被复制到新创建的实例中。然而,在 JavaScript 中并非如此。JS 使用原型的机制来实现面向对象。

与其他 OOP 语言相比,JavaScript 对象继承了不同的特性。本节演示这种差异,描述原型链如何工作,并展示如何使用 prototype 属性向现有构造函数添加方法。

JavaScript 是一种基于原型的语言。这意味着每个对象,比如说 A,都有一个名为 prototype 的对象,该对象从这个对象派生属性和方法。同样,对象 A 的原型对象也可能有一个原型对象,依此类推。这就是所谓的原型链。在 JavaScript 中,方法和属性驻留在对象的构造函数中。在对象的实例和构造函数之间创建一个连接。

为了更好地理解原型概念,考虑下面的例子,它有一个简单的播放器函数:

function Player(pname,weight,height)
{
}

接下来,创建一个对象实例 player1:

var player1 = new Player('James', 100 , 20);

在 web 浏览器控制台中显示 player1 的内容会产生如图 8-5 所示的输出。

A394309_1_En_8_Fig5_HTML.jpg

图 8-5。播放器 1 的控制台输出

如您所见,player1 原型对象中的成员是 pname、weight 和 height。Thes e 驻留在播放器构造器的原型对象上,也就是对象。见图 8-6 。

A394309_1_En_8_Fig6_HTML.jpg

图 8-6。玩家 1、玩家和对象

假设您使用驻留在 Object 中的 player1 调用一个方法,比如 valueOf。在这种情况下,JS 首先检查 Player1 对象是否具有方法 valueOf。因为这不是真的,JS 接下来在 Player 对象中搜索 valueOf 方法。该方法也不存在于 Player 对象中。所以 JS 再去搜索 Player 的构造器的原型对象。(这是 Object。)对象包含您正在搜索的给定方法。

为了更好地理解属性的继承,请看一下 console.log 中的 Object。

对象中存在大量属性。但是,所有这些在 player1 对象中都不可用。继承的属性驻留在 Object 的 prototype 属性上。(即,它们不是简单地从 Object 开始,而是从 Object.prototype 开始)。“原型”的属性的“值”实际上是一个对象,它包含一组可以沿着继承(原型)链继承的属性和方法。例如,Object.prototype.valueOf()方法存在于从 Object 继承的任何对象中。另一方面,从 Object 继承的对象不会继承 Object.key 方法。

回到前面的例子,播放器的原型如图 8-7 所示。

A394309_1_En_8_Fig7_HTML.jpg

图 8-7。玩家原型

图 8-7 中没有太多东西,因为在播放器构造函数中没有定义任何方法。

接下来,看看使用 Chrome 控制台显示的 Object.prototype,如图 8-8 所示。

A394309_1_En_8_Fig8_HTML.jpg

图 8-8。对象.原型

假设您添加了以下语句:

var another_player  = Object.create(player1);

Object 的 create 方法从原型对象创建一个新对象。

如您所见,player2 是使用 player1 创建的。假设您输入以下内容:

console.log(another_player.__proto__);

该语句的输出如图 8-9 所示。

A394309_1_En_8_Fig9_HTML.jpg

图 8-9。proto of

每个对象都有一个名为 constructor 的属性,该属性链接到构造函数(用于创建实例)。player1.constructor 和 player2.constructor 的输出如图 8-10 所示。

A394309_1_En_8_Fig10_HTML.jpg

图 8-10。Player1 和 Player2 构造函数

如您所见,这两个函数都返回了播放器构造函数。

还可以使用构造函数属性(以及必要的参数)创建一个新的实例。考虑这个例子:

var player3 =  new player1.constructor('John Mann', 100, 11);

此示例将 constructor 属性用作一个函数,包括括号和 new 关键字。

当您输出新对象 player3 的内容时,如下所示,它正常工作:

player3.pname
player3.weight
person3.height

构造函数属性还可以以另一种方式使用。您可以修改构造函数的 prototype 属性,将新方法添加到构造函数的原型中:

Player.prototype.hello = function(){
   alert('I am Player');
}
Player1.hello();

运行 hello 方法将显示一条警告消息,提示我是玩家。值得注意的是,整个继承链可能会在运行时改变,从而使 hello()方法在所有从 constructor Player 派生的实例上都可用。

为了更好地理解,请考虑以下代码:

function Player(pname, weight, height) {
 this.pname = pname;  this.height = height; this.weight = weight;
};
var player1 = new Player('James', 32,100);
Player.prototype.hello = function() {
  alert('I am' + this.pname);
}
player1.hello();

这个例子从一个构造函数 Player 开始,然后使用 Player 的 prototype 属性定义了一个新方法 hello。该方法在 player1 对象实例上可用。该功能已自动更新。如前所述,这证实了原型链。JS 首先在对象实例中寻找方法,然后在原型链上向上移动。

定义属性的另一种方法是使用 prototype 属性。例如,您可以向 Player 对象添加一个城市属性:

Player.prototype.city = 'New York';

然而,这并不常见。更常见的方法是在构造函数中指定属性,而各种方法使用原型。在这种情况下,代码很容易理解,因为所有属性都驻留在构造函数中,而方法在后面的不同块中定义:

function Player(a, b, c, d) {
  // property definitions
};

Player.prototype.func1 = function() { ... }
Player.prototype.func2 = function() { ... }

原型遗传

既然您对继承和工作原型有了一些概念,那么您就可以看到这些概念的实际应用了。如前所述,JavaScript 使用基于原型的继承。这涉及到使用原型链链接继承的对象。本节将向您展示一种在 JavaScript 中实现继承概念的技术。

从前面创建的 Player 构造函数开始,记住在 Player 中只指定了属性 pname、weight 和 height:

function Player(pname, weight, height) {
  this.pname = pname;
  this.weight = weight;
  this.height = height;
};

现在,在构造函数的 prototype 属性上定义一个方法 tellname:

Player.prototype.tellname = function() {
   alert('My name is ' + this.pname + ' and I am a Player' );
};

tellname 函数将在一个警告框中显示玩家的名字。

接下来,假设您想要创建一个名为 CricketPlayer 的构造函数,它继承前面定义的 Player 的所有成员。此外,您希望它包含一个名为 cricketcounty 的新属性和一个名为 tellme 的更新方法。

首先,创建一个 CricketPlayer 构造函数,如下所示:

function CricketPlayer(pname, weight, height, cricketcounty) {
  Player.call(this, pname, weight, height);
  this.cricketcounty = cricketcounty;
}
注意

不建议有很多层次的继承。过多的级别可能会导致很多混乱,也会在调试时带来很多困难。正如您将看到的,call()方法使您能够调用位于构造函数之外但在同一上下文中的函数。

call 方法用于链接构造函数。在这种情况下,它调用 Player 的构造函数。第一个参数 this 指向当前函数,其余参数用于为被调用的函数(即播放器构造函数)参数提供值。

最后是 cricketcounty 属性,它不在 Player 中,但只特定于 CricketPlayer 函数。实际上,您正在 CricketPlayer 构造函数中执行 Player 构造函数。

这与下面的代码块相同:

function CricketPlayer(pname, weight, height, cricketcounty) {
  this.pname = pname ;
  this.weight = weight ;
  this.height = height;
  this.cricketcounty = cricketcounty;
}

但是,这不包括可重用性特性,所以您不应该使用它。

现在您已经有了一个构造函数,该构造函数具有指向构造函数的 prototype 属性,添加下面一行,以便 CricketPlayer()函数继承播放器的 prototype 属性中定义的方法:

CricketPlayer.prototype = Object.create(Player.prototype);

在这里,create 方法用于根据 Player.prototype 指向的值创建一个新对象。新对象被分配给 CricketPlayer.prototype,以便 CricketPlayer.prototype 继承 Player.prototype 中的方法。在此之前,CricketPlayer.prototype 等于 Player()(因为 CricketPlayer.prototype 被分配给一个作为 Player.prototype 对象的对象)。这可能会有问题,因此您需要在末尾添加以下语句:

CricketPlayer.prototype.constructor = CricketPlayer;
CricketPlayer.prototype.tellname = function() {
   alert('My name is ' + this.pname + 'and I am a cricket Player of' + this.cricketcounty + '.' );
};

最后,您可以添加以下语句:

var cper = new CricketPlayer('Jon Reed', 100, 190, ' Surrey County');
cper.tellname();

完整的继承代码如清单 8-5 所示。

清单 8-5。完整的继承代码
<html>
   <body>
      <script>

function Player(pname, weight, height) {
  this.pname = pname;
  this.weight = weight;
  this.height = height;
};

function CricketPlayer(pname, weight, height, cricketcounty) {
  Player.call(this, pname, weight, height);
  this.cricketcounty = cricketcounty;
}

Player.prototype.tellname = function() {
   alert('My name is ' + this.pname + ' and I am a Player' );
};

CricketPlayer.prototype = Object.create(Player.prototype);
CricketPlayer.prototype.constructor = CricketPlayer;

CricketPlayer.prototype.tellname = function() {
   alert('My name is ' + this.pname + ' and I am a cricket Player of' + this.cricketcounty + '.' );
};

var per = new Player('James Wood', 120,20);
var cper = new CricketPlayer('Jon Reed', 100, 190, ' Surrey County');
per.tellname();
cper.tellname();

     </script>
  </body>
</html>

此时,per 和 cper 内容如图 8-11 所示。

A394309_1_En_8_Fig11_HTML.jpg

图 8-11。console.log 中 per 和 cper 的内容

前三个成员 pname、height 和 weight 是从 Player 继承的,而 cricketcounty 是在 CricketPlayer 级别定义的。方法 tellname 在板球运动员级别被重新定义。

在清单 8-5 的最后,使用 new 关键字定义了两个对象 per 和 cper,然后为对象 per 和 cper 调用 tellname 方法。这每次都会调用不同的方法。结果出现两种不同的警告框,如图 8-12 和 8-13 所示。

A394309_1_En_8_Fig12_HTML.jpg

图 8-12。方法 tellname 类播放器的输出

A394309_1_En_8_Fig13_HTML.jpg

图 8-13。方法 tellname 类板球运动员的输出

如您所见,这两种方法的输出完全是不同的格式。这是多态性的一个演示。

摘要

本章首先提供了面向对象编程的概述,然后向您展示了 OOP 是如何在 JS 中实现的,以及相关的语法。它讨论了 this 操作符,然后讨论了创建对象的各种方法,接着是使用 new 关键字的实例化步骤。本章最后介绍了使用原型在 JS 中实现的继承。

在第九章中,你将详细看到 JS 的许多内置对象,以及它们提供的属性和方法,JS 开发者可以使用这些属性和方法来减少他们的编程时间和工作量。

九、对象

在 JavaScript 中,对象是一个无序的属性列表。属性由名称和值组成,也可以是函数。在这种情况下,该函数称为方法。本章涵盖了用 JavaScript 编码时需要熟悉的一些标准对象。它还提供了它们的属性和最可能使用它们的方法的例子。本章还介绍了数组、布尔对象、字符串对象和日期对象。

重新访问的对象

清单 9-1 给出了一个对象的简单例子。

清单 9-1。对象示例
<html>
   <body>
      <script>
          var book = {novel: "Secret", author: "Rhonda Byrne", publicationDate: "Nov 2006"};
          console.log(book.novel +  " this book is of author " +  book.author);
     </script>
  </body>
</html>

如本例所示,一个对象包含一个项目列表,列表中的每个项目都有一个名称-值对。这些属性的名称是 novel、author 和 publicationDate,每个属性都被赋予一个值。该代码的输出如图 9-1 所示。

A394309_1_En_9_Fig1_HTML.jpg

图 9-1。输出

排列

正如您在本书前面看到的,数组对象允许您在一个变量名下存储多个值。索引号从 0 开始,数组的第一个元素表示为[0],第二个表示为[1],依此类推。

数组创建的语法是

var arrayName = [value1, value2, .... Valuen]

考虑清单 9-2 中数组文字的简单例子。

清单 9-2。数组文字示例
<html>
   <body>
      <script>
          var countries = ["India", "Germany", "Scotland"];
          console.log(countries);
     </script>
  </body>
</html>

此示例将变量 countries 声明为一个数组,它包含元素 India、Germany 和 Scotland。接下来,使用 console.log 方法打印 countries 数组。正如您所看到的,这个例子没有指定任何要打印的索引或元素。这段代码给出了一个数组的最大长度。

清单 9-2 的输出如图 9-2 所示。

A394309_1_En_9_Fig2_HTML.jpg

图 9-2。输出

如果在 console.log 语句中没有指定数组的元素索引,则显示元素的总数,而不是每个元素的内容。

现在考虑清单 9-3 中带有索引的数组的相关示例。

清单 9-3。带索引的数组示例
<html>
   <body>
      <script>
          var countries = ["India", "Germany", "Scotland"];
          console.log(countries[0], countries[1], countries[2]);
     </script>
  </body>
</html>

使用与清单 9-2 中相同的起始基本代码,这个例子展示了如何通过指定数组索引号来访问数组的各个元素。该代码的输出如图 9-3 所示。

A394309_1_En_9_Fig3_HTML.jpg

图 9-3。输出

数组也可以使用新的关键字来定义,如清单 9-4 中的例子所示。

清单 9-4。带有索引示例的新数组
<html>
   <body>
      <script>
          var countries = new Array( "India", "Germany", "Scotland" );
          console.log(countries[0], countries[1], countries[2]);
     </script>
  </body>
</html>

这采用了相同的初始示例,并添加了关键字 new。两个例子的工作方式完全相同;唯一的区别是清单 9-4 创建了一个新数组。该代码的输出如图 9-4 所示。

A394309_1_En_9_Fig4_HTML.jpg

图 9-4。输出
注意

如果可能的话,创建没有新关键字的数组,这样会更快。

数组对象的属性

表 9-1 列出并描述了数组对象的三个最常用属性。

表 9-1。数组对象的属性
|

财产

|

描述

|
| --- | --- |
| 构造器 | 返回数组函数 |
| 指数 | 返回字符串中匹配项的从零开始的索引 |
| 长度 | 给出数组的长度 |

接下来将更详细地描述构造函数和长度属性。

属性构造函数

构造函数属性的语法是

array.constructor

这将返回函数 Array(){[本机代码] }。清单 9-5 中显示了一个简单的例子。

清单 9-5。数组构造函数属性示例
<html>
   <body>
      <script>
               var countries = new Array( "Germany", "India", "Scotland" );
               console.log("countries.constructor is:" + countries.constructor);
      </script>
   </body>
</html>

此示例使用 new 关键字声明数组 countries,然后使用 console.log 显示 countries.constructor。此代码的输出如图 9-5 所示。

A394309_1_En_9_Fig5_HTML.jpg

图 9-5。输出

属性长度

顾名思义,length 属性包含数组的长度。元素的数量以整数形式指定。长度属性的语法是

array.length

这将返回数组长度,即元素的总数。清单 9-6 提供了这个属性的一个工作实例。

清单 9-6。数组长度属性示例
<html>
   <body>
      <script>
               var countries = new Array( "Germany", "India", "Scotland", "Austria" );
               console.log("Length of array is:" + countries.length);
      </script>
   </body>
</html>

清单 9-6 的输出如图 9-6 所示。

A394309_1_En_9_Fig6_HTML.jpg

图 9-6。输出

数组方法

数组对象包含许多方法,表 9-2 中列出并描述了其中一些方法。

表 9-2。数组对象的方法
|

方法

|

描述

|
| --- | --- |
| concat() | 合并两个或多个数组并返回新数组。 |
| forEach() | 对数组中的每个元素执行指定的函数。 |
| 加入() | 将数组的元素组合成一个字符串。 |
| lastIndexOf() | 返回在数组中找到给定元素的最后一个索引。如果元素不在数组中,则返回-1。 |
| 流行() | 移除并返回数组的最后一个元素。 |
| 推送() | 将一个或多个元素添加到数组末尾,并返回新的数组长度。 |
| 反向() | 反转数组的顺序。 |
| toString() | 以字符串形式返回数组的组成部分。 |
| 排序() | 对数组元素进行排序。 |
| shift() | 移除第一个元素并返回更新后的数组。 |
| 切片() | 按照位置的指定剪切数组的一部分,并以字符串的形式返回数组。 |

下面是对 concat 和 pop 方法的更详细的描述。

方法串联

concat()方法的语法是

array.concat(arr1, arr2, ..., arrN);

这里,arr1 和 arr2 是数组的元素。这将返回另一个包含串联值的数组。清单 9-7 展示了一个使用这种方法的例子。

清单 9-7。Array concat()方法示例
<html>
   <body>
      <script>
               var countries = ["Germany", "Scotland", "Austria"];
               var continents = ["Europe", "Australia", "Africa"];
               var world = countries.concat(continents);
               console.log(" The world map has countries & continents:" + world);
      </script>
   </body>
</html>

此示例声明了两个数组,一个包含可变的国家,另一个包含可变的洲。然后使用 concat()方法组合这两个数组元素,形成一个新数组。

清单 9-7 的输出如图 9-7 所示。

A394309_1_En_9_Fig7_HTML.jpg

图 9-7。输出

方法弹出

pop 方法从数组中移除最后一个元素并返回它的值。pop()方法的语法是

array.pop();

这将返回从数组中移除的元素或值。清单 9-8 提供了 pop()方法的一个例子。

清单 9-8。数组 pop()方法示例
<html>
   <body>
      <script>
               var countries = ["Germany", "Scotland", "Austria"];
               var value = countries.pop();
               console.log(" Removed value from array is:" + value);
               var value = countries.pop();
               console.log(" Removed value from array is:" + value);
      </script>
   </body>
</html>

这个例子用一些数组元素声明变量 countries,然后使用 pop()方法。该值存储在变量值中,然后显示出来。该代码的输出如图 9-8 所示。

A394309_1_En_9_Fig8_HTML.jpg

图 9-8。输出

布尔代数学体系的

布尔对象代表两个值:真或假。布尔值的语法是

Boolean (value)

清单 9-9 显示了布尔对象的一个例子。

清单 9-9。布尔对象示例
<html>
   <body>
      <script>

              function myBoolean() {
              console.log(10 < 15);
              }
             myBoolean();
     </script>
  </body>
</html>

此示例比较布尔值。如果 10 小于 15,代码返回 true 如果不是,则返回 false。清单 9-9 的输出如图 9-9 所示。

A394309_1_En_9_Fig9_HTML.jpg

图 9-9。输出

布尔属性

布尔对象的属性在表 9-3 中列出并描述。

表 9-3。布尔属性
|

财产

|

描述

|
| --- | --- |
| 构造器 | 对象的构造函数 |
| 原型 | 允许开发人员添加属性和方法 |

布尔方法

现在让我们讨论布尔对象的一些有用的方法。

方法值

valueOf()方法的语法是

boolean.valueOf()

这将返回指定布尔对象的原始值。清单 9-10 显示了一个这样的例子。

清单 9-10。布尔值 Of()方法示例
<html>
   <body>
      <script>
              var value = Boolean(10 < 15);
              var num = value.valueOf();
              console.log( "Value of Boolean is:" + num.valueOf() );
     </script>
  </body>
</html>

此示例分配变量值,然后使用 valueOf()方法检查布尔表达式是真还是假。输出如图 9-10 所示。

A394309_1_En_9_Fig10_HTML.jpg

图 9-10。输出

线

在 string 对象中,可以存储一系列字符,如下例所示:

var textString = "JavaScript language" or 'JavaScript language'

如图所示,您可以用单引号或双引号来编写这个系列。

弹簧属性

表 9-4 列出并描述了字符串对象的一些属性。

表 9-4。String 对象的属性
|

财产

|

描述

|
| --- | --- |
| 长度 | 字符串的长度 |
| 构造器 | 返回对字符串函数的引用 |
| 原型 | 允许开发人员向对象添加属性和方法 |

下面是对长度属性的更详细的描述。

属性长度

属性长度的语法是

string.length

这给出了字符串中的字符数,包括空格和空白。考虑清单 9-11 中的简单例子。

清单 9-11。字符串长度属性示例
<html>
   <body>
      <script>
              var text = "JavaScript Object";
              var strLength = text.length;
              console.log( "The string length is:" + strLength );
     </script>
  </body>
</html>

这个例子显示了字符串的长度。它声明了变量 text 并给它分配了一个字符串。然后,使用属性 length 确定给定字符串中的字符数。该代码的输出如图 9-11 所示。

A394309_1_En_9_Fig11_HTML.jpg

图 9-11。输出

字符串方法

表 9-5 中列出并描述了字符串方法。

表 9-5。字符串方法
|

方法

|

描述

|
| --- | --- |
| concat() | 组合两个或多个字符串。 |
| 索引() | 在字符串中搜索给定文本和主字符串中的起始位置。如果搜索不成功,它返回-1。 |
| 匹配() | 根据正则表达式匹配字符串时,返回“匹配字符串”。 |
| 替换() | 检查正则表达式后,用新字符串替换一个字符串。 |
| 夏拉特() | 返回给定位置的字符。 |
| 切片() | 基于指定的开始和结束位置移除字符并提取字符串的一部分(不包括结束字符)。 |
| 拆分() | 根据给定的分隔符(如“,”)将字符串分成多个子字符串,并以数组形式返回它们。 |
| 搜索() | 在字符串中搜索值或正则表达式。如果找到,则返回匹配的位置。 |
| toUpperCase() | 转换为大写。 |
| toLowerCase() | 转换为小写。 |
| substr() | 也用于提取。但是,起始位置和要提取的字符数是指定的。 |
| 包括() | 检查字符串是否包含某个字符或一组字符。 |
| endsWith() | 检查字符串是否以某个字符或一组字符结尾。 |

下面将更详细地描述 chartAt、repeat 和 slice 方法。

方法特征

方法 charAt()的语法是

String.charAt(ind)

这将返回给定位置的字符。考虑清单 9-12 中的 chartAt()例子。

清单 9-12。String charAt()方法示例
<html>
   <body>
      <script>
              var text = "JavaScript Object";
              var char = text.charAt(2);
              console.log( "The character at position 2 is:" + char );
     </script>
  </body>
</html>

我们现在使用同一个例子来展示 charAt()方法,它标识给定索引号处的字符。(注意数组的基数是 0,所以如果你把 2 作为索引,你会得到第三个字符。)

列表 9-12 的输出如图 9-12 所示。

A394309_1_En_9_Fig12_HTML.jpg

图 9-12。输出

方法重复

方法 repeat 的语法是

String.repeat(n)

这里,字符串内容重复的次数是通过数字 n 指定的。这将返回包含重复文本的字符串。为了更好地理解这是如何工作的,考虑清单 9-13 中的例子。

清单 9-13。字符串重复()方法示例
<html>
   <body>
      <script>
              var text = "JavaScript Object";
              var string = text.repeat(2);
              console.log( "The string repeats twice:" + string );
     </script>
  </body>
</html>

在这种情况下,声明的字符串“JavaScript Object”通过方法 repeat()写了两次。该代码的输出如图 9-13 所示。

A394309_1_En_9_Fig13_HTML.jpg

图 9-13。输出

方法切片

方法切片的语法是

string.slice( startslice [, endSlice] );

这里,startslice 是在移除之前要提取的部分的起始位置编号,endslice 是可选的,用于从右侧移除字符串的一部分。索引(位置)是从字符串的右侧指定的(即从字符串的末尾向左计数)。之后的所有内容都被删除,不作为返回字符串的一部分发送。这个数字作为负号传递。所以,-4 表示最后四个字符。

考虑清单 9-14 中切片方法的例子。

清单 9-14。String slice()方法示例
<html>
   <body>
      <script>
              var text = "JavaScript is also Object oriented";
              var string = text.slice(4, -4);
              console.log( "The new string is:" + string );
     </script>
  </body>
</html>

此示例声明变量 text,并为其分配字符串。起始和结束索引号在 slice 方法中指定,代码将从字符串中提取它们之间的字符。输出如图 9-14 所示。

A394309_1_En_9_Fig14_HTML.jpg

图 9-14。输出

日期

日期对象帮助我们处理日期和时间。有四种方法可以创建该对象:

new Date( )
new Date(milliseconds)
new Date(datestring)
new Date(year,month,date[,hour,minute,second,millisecond ])

日期属性

表 9-6 中列出并描述了日期属性。

表 9-6。日期属性
|

财产

|

描述

|
| --- | --- |
| 构造器 | 构造器 |
| 原型 | 允许开发人员添加属性和方法 |

属性构造函数

constructor 属性返回创建 date 对象原型的函数。构造函数的语法是

date.constructor

考虑清单 9-15 中的构造函数属性的例子。

清单 9-15。日期构造函数属性示例
<html>
   <body>
      <script>
             var tdyDate = new Date();
             console.log(tdyDate.constructor);
     </script>
  </body>
</html>

这个例子用一个新的日期声明了变量 tdyDate。构造函数属性返回函数日期。输出如图 9-15 所示。

A394309_1_En_9_Fig15_HTML.jpg

图 9-15。代码输出

日期方法

表 9-7 中列出并描述了日期对象的一些常用方法。

表 9-7。日期对象的方法
|

方法

|

描述

|
| --- | --- |
| getDate() | 给出日期中的某一天(例如 1,2,3,… 31) |
| getDay() | 以数字的形式给出星期几(例如,从 0,1,2,… 6) |
| getFullYear() | 返回日期中的年份(如 1978 年) |
| getHours() | 给出日期的小时(例如,0,1,… 23) |
| getMinutes() | 返回日期的分钟数(例如,0,1,2,… 59) |
| getMonth() | 给出日期对象的月份(例如,0,1,2,11) |
| getSeconds() | 返回秒数(例如,0,1,2,3,… 59) |

对于表 9-7 中除 getDay()之外的所有方法,都有对应的 set 方法,如 setDate、setFullYear 等。

现在让我们看几个例子。

通过 getDay()方法使用属性原型

如前所述,prototype 属性允许您向对象添加属性和方法,无论它是布尔值、字符串、日期还是其他。使用 prototype 属性的语法是

Object.prototype.name = value

清单 9-16 展示了如何向日期对象添加一个新方法。

清单 9-16。日期原型属性示例
<html>
   <body>
      <script>
          function myDay() {
             var tdyDay = new Date();
             tdyDay.today();
             console.log(tdyDay.Day);
          }
            Date.prototype.today = function() {
            switch (this.getDay()) {
            case 0:
                    this.Day = "Sunday";
                    break;
            case 1:
                    this.Day = "Monday";
                    break;
            case 2:
                    this.Day = "Tuesday";
                    break;
            case 3:
                    this.Day = "Wednesday";
                    break;
             case 4:
                    this.Day = "Thursday";
                    break;
             case 5:
                    this.Day = "Friday";
                    break;
             case 6:
                    this.Day = "Saturday";
                    break;
          }
       };
       myDay();
     </script>
  </body>
</html>

本示例向 date 对象添加一个新函数 today。在这个函数中,首先 getDay 函数使用。基于此,将显示一天的名称,例如 0 表示星期一,1 表示星期二,依此类推。在函数 myDay 中,定义了一个新的日期,并调用了 today 方法。

列表 9-16 的输出如图 9-16 所示。

A394309_1_En_9_Fig16_HTML.jpg

图 9-16。输出

方法 setMonth

setMonth()方法的语法是

Date.setMonth(monthValue[, dayValue])

这里,monthValue 表示从 1 月到 12 月的月份,但是为它传递的整数值必须是从 0 到 11,其中 0 表示 1 月,以此类推。dayValue 参数是可选的,表示一个月中的日期,例如 1,2,3 … 31。

清单 9-17 展示了如何在程序中使用这个方法。

清单 9-17。Date setMonth()方法示例
<html>
   <body>
      <script>
              var d1 = new Date( "March 23, 2017 11:35:00" );
              d1.setMonth( 1 );
              console.log( "The date is set to: " + d1 );
     </script>
  </body>
</html>

此示例声明日期 d1,并使用 new 关键字为其赋值。然后它调用方法 setMonth()并传递值 1。这表示日期的新月份值。本示例将二月的新值设置为 1。

该代码的输出如图 9-17 所示。

A394309_1_En_9_Fig17_HTML.jpg

图 9-17。程序输出

摘要

本章介绍了使用 JavaScript 时会遇到的几个基本对象,包括数组、布尔值、字符串和日期。它描述了一些与它们相关的属性和方法,并向您展示了如何使用它们来编写 JS 代码。

在第十章,你将探索 JSON 格式。

十、JavaScript 对象符号(JSON)

本章介绍了使用 JavaScript 对象符号的各种方法。它从 JSON 的概述开始,然后深入到 JSON 中使用的数据类型的细节。然后您将看到 JSON 数组和对象如何在 JS 程序中工作。最后,您将看到 JSON 对象的两个有用的方法,parse 和 stringify。

JSON:概述

JSON 是一种数据表示形式,允许您以有组织的方式安排可互换的信息。JSON 是文本形式的(人类可读的),驻留在一个文件中。与 json 文件相关联的常用文件扩展名是. JSON。

注意

除了 JavaScript,JSON 还可以用于 Java、Python、Perl 等。JSON 可以用来在浏览器和服务器之间交换数据。

JSON 的语法是 JavaScript 语法的一个子集,由具有名称和值对的数据组成。

对象包含在大括号{}中,用逗号分隔,而对象和每个名称后跟冒号(

标签:console,函数,示例,JavaScript,清单,ABAP,var,SAP,log
From: https://www.cnblogs.com/apachecn/p/18448094

相关文章

  • Vue Javascript 导出Excel:SheetJS/js-xlsx json_to_sheet xlsx 修改表头名称和展示的
     import*asXLSXfrom'xlsx';//展示的顺序,把data中对象的属性按照你想要的顺序排放就可以了,constheader=["pId","dID"]//展示的名称constheaderDisplay={pId:"项编号",dID:"D编号"};//将表头放剑原始数据里面去,要保证表头在数......
  • [JavaScript] this 关键字
    全局作用域在浏览器中,如果在全局作用域下使用this,它将指向window对象;在Node.js环境中,则指向global对象。方法调用当一个函数作为对象的方法被调用时,this会指向该对象。constobj={name:"Alice",greet:function(){console.log(`Hello,${this.name}`)......
  • 从 JavaScript 到 OCaml:浅浅浅总结一下函数式编程
    背景这几天突击了一下Cornell的cs3110;抽了两个下午刷完了Chapter3,4,5的课后习题,很有感触。结合自己浅薄的函数式编程理解和贫瘠的JavaScript/TypeScript开发经历,总结一下自己第一阶段的函数式编程学习经历。......
  • 盘点五大热门JavaScript图表库,助你高效开发!
    1、Chart.jsChart.js是一个简单、灵活的图表库,支持8种图表类型(如折线图、柱状图、饼图等)。它使用HTML5Canvas元素来渲染图表,并且有良好的文档和社区支持。使用方法:npminstallchart.jsvue-chartjs然后在你的Vue组件中使用:<template><div><line-chart:data......
  • 掌握防抖与节流:如何用JavaScript封装通用函数
    在日常前端开发中,我们经常会遇到一些频繁触发的事件,如窗口调整大小、滚动条滚动、输入框输入等。为了提高页面性能和用户体验,我们需要对这些事件进行优化。本文将介绍如何使用JavaScript封装通用的防抖和节流函数。一、什么是防抖(Debounce)和节流(Throttle)?防抖(Debounce):当持续......
  • 总结28个令人惊艳的JavaScript单行代码
    1.阶乘计算使用递归函数计算给定数字的阶乘。12constfactorial=n=>n===0?1:n*factorial(n-1);console.log(factorial(5));//输出120 2.判断一个变量是否为对象类型1constisObject=variable===Object(variable);......
  • JavaScript-快速语法参考-全-
    JavaScript快速语法参考(全)原文:JavaScriptQuickSyntaxReference协议:CCBY-NC-SA4.0一、使用JavaScript要开始试验JavaScript,您应该安装一个支持这种语言的集成开发环境(IDE)。有很多不错的选择,比如NetBeans、Eclipse、VisualStudio、括号。在本书中,我们将使用NetBe......
  • JavaScript-正则表达式入门指南-全-
    JavaScript正则表达式入门指南(全)原文:IntroducingRegularExpressions协议:CCBY-NC-SA4.0一、正则表达式简介为了开始介绍正则表达式,我将从一个例子开始。这是一个你已经经历了几百次的问题。当您在线输入客户数据时,许多web表单会要求您提供电子邮件地址。为了避免输入......
  • JavaScript笔记
    基操数据类型原始类型对象类型MapandSet流程控制函数及面向对象函数方法常用内部对象面向对象编程(OOP)操作BOM元素操作DOM元素(I)操作表单jQuery基操js作为一种脚本语言,可以嵌入到HTML页面中js是双标签,可以写多行,也可以写一行内部标签<script>......
  • 教你如何免费获取股票数据用python、JavaScript (Node.js)、JAVA等多种语言的实例代码
    ​近一两年来,股票量化分析逐渐受到广泛关注。而作为这一领域的初学者,首先需要面对的挑战就是如何获取全面且准确的股票数据。因为无论是实时交易数据、历史交易记录、财务数据还是基本面信息,这些数据都是我们进行量化分析时不可或缺的宝贵资源。我们的核心任务是从这些数据......