JavaScript 教程 (详细 全面)

线程

文章目录

ceil向上取整


JavaScript 是什么?JavaScript 简介

JavaScript(简称“JS”)是当前最流行、应用最广泛的客户端脚本语言,用来在网页中添加一些动态效果与交互功能,在 Web 开发领域有着举足轻重的地位。

软件工程

JavaScript 与 HTML 和 CSS 共同构成了我们所看到的网页,其中:

交互

  • HTML 用来定义网页的内容,例如标题、正文、图像等;
  • CSS 用来控制网页的外观,例如颜色、字体、背景等;
  • JavaScript 用来实时更新网页中的内容,例如从服务器获取数据并更新到网页中,修改某些标签的样式或其中的内容等,可以让网页更加生动。

1. JavaScript 的历史

JavaScript 最初被称为 LiveScript,由 Netscape(Netscape Communications Corporation,网景通信公司)公司的布兰登·艾奇(Brendan Eich)在 1995 年开发。在 Netscape 与 Sun(一家互联网公司,全称为“Sun Microsystems”,现已被甲骨文公司收购)合作之后将其更名为了 JavaScript。在这里插入图片描述
之所以将 LiveScript 更名为 JavaScript,是因为 JavaScript 是受 Java 的启发而设计的,因此在语法上它们有很多相似之处 ,JavaScript 中的许多命名规范也都借鉴自 Java,还有一个原因就是为了营销,蹭 Java 的热度。

代码自动生成

同一时期,微软和 Nombas(一家名为 Nombas 的公司)也分别开发了 JScript 和 ScriptEase 两种脚本语言,与 JavaScript 形成了三足鼎立之势。它们之间没有统一的标准,不能互用。为了解决这一问题,1997 年,在 ECMA(欧洲计算机制造商协会)的协调下,Netscape、Sun、微软、Borland(一家软件公司)组成了工作组,并以 JavaScript 为基础制定了 ECMA-262 标准(ECMAScript)。

个人健康监控系统

第二年,ISO/IEC(国际标准化组织及国际电工委员会)也采用了 ECMAScript 作为标准(即 ISO/IEC-16262)。

ERC1155 批量转移

2. JavaScript 与 ECMAScript 的关系

ECMAScript(简称“ES”)是根据 ECMA-262 标准实现的通用脚本语言,ECMA-262 标准主要规定了这门语言的语法、类型、语句、关键字、保留字、操作符、对象等几个部分,目前 ECMAScript 的最新版是 ECMAScript6(简称“ES6”)。

笔试

至于 JavaScript,有时人们会将 JavaScript 与 ECMAScript 看作是相同的,其实不然,JavaScript 中所包含的内容远比 ECMA-262 中规定的多得多,完整的 JavaScript 是由以下三个部分组成:

ios证书

  • 核心(ECMAScript):提供语言的语法和基本对象;
  • 文档对象模型(DOM):提供处理网页内容的方法和接口;
  • 浏览器对象模型(BOM):提供与浏览器进行交互的方法和接口。

3. 如何运行 JavaScript

作为一种脚本语言,JavaScript 代码不能独立运行,通常情况下我们需要借助浏览器来运行 JavaScript 代码,所有 Web 浏览器都支持 JavaScript。

数据链路层

除了可以在浏览器中执行外,也可以在服务端或者搭载了 JavaScript 引擎的设备中执行 JavaScript 代码,浏览器之所以能够运行 JavaScript 代码就是因为浏览器中都嵌入了 JavaScript 引擎,常见的 JavaScript 引擎有:

优化

  • V8:Chrome 和 Opera 中的 JavaScript 引擎;
  • SpiderMonkey:Firefox 中的 JavaScript 引擎;
  • Chakra:IE 中的 JavaScript 引擎;
  • ChakraCore:Microsoft Edge 中的 JavaScript 引擎;
  • SquirrelFish:Safari 中的 JavaScript 引擎。
    JavaScript 的特点

4. JavaScript 具有以下特点

1) 解释型脚本语言
JavaScript 是一种解释型脚本语言,与 C、C++ 等语言需要先编译再运行不同,使用 JavaScript 编写的代码不需要编译,可以直接运行。
2) 面向对象
JavaScript 是一种面向对象语言,使用 JavaScript 不仅可以创建对象,也能操作使用已有的对象。
3) 弱类型
JavaScript 是一种弱类型的编程语言,对使用的数据类型没有严格的要求,例如您可以将一个变量初始化为任意类型,也可以随时改变这个变量的类型。
4) 动态性
JavaScript 是一种采用事件驱动的脚本语言,它不需要借助 Web 服务器就可以对用户的输入做出响应,例如我们在访问一个网页时,通过鼠标在网页中进行点击或滚动窗口时,通过 JavaScript 可以直接对这些事件做出响应。
5) 跨平台
JavaScript 不依赖操作系统,在浏览器中就可以运行。因此一个 JavaScript 脚本在编写完成后可以在任意系统上运行,只需要系统上的浏览器支持 JavaScript 即可。

系统

Node.js 是什么?Node.js 简介

JavaScript 诞生于 1995 年,几乎是和互联网同时出现;Node.js 诞生于 2009 年,比 JavaScript 晚了 15 年左右。

Stream流式编程

在 Node.js 之前,JavaScript 只能运行在浏览器中,作为网页脚本使用,为网页添加一些特效,或者和服务器进行通信。有了 Node.js 以后,JavaScript 就可以脱离浏览器,像其它编程语言一样直接在计算机上使用,想干什么就干什么,再也不受浏览器的限制了。

前后端分离商城

Node.js 不是一门新的编程语言,也不是一个 JavaScript 框架,它是一套 JavaScript 运行环境,用来支持 JavaScript 代码的执行。用编程术语来讲,Node.js 是一个 JavaScript 运行时(Runtime)。
在这里插入图片描述
现在的 JavaScript 除了用于 Web 前端编程(网页编程),还能干很多事情,比如:

线性回归

  • 开发网站后台,这原本是 PHP、Java、Python、Ruby 等编程语言擅长的;
  • 开发 GUI 程序,也就是我们常说的带界面的电脑软件,比如 QQ、360、迅雷等;
  • 手机 APP,包括 Android APP、iOS APP;
  • CLI 工具,也就是不带界面的命令行程序。

你看,学会了 JavaScript,你不但是全栈工程师,甚至还将无所不能,这都是 Node.js 带给我们的。

python绘制玫瑰花

Node.js 官网中文版:https://nodejs.org/zh-cn/

获取UID

1. 运行时是什么?

所谓运行时,就是程序在运行期间需要依赖的一系列组件或者工具;把这些工具和组件打包在一起提供给程序员,程序员就能运行自己编写的代码了。

TA-Lib

对于 JavaScript 来说,它在运行期间需要依赖以下组件:
1) 解释器
JavaScript 是一种脚本语言,需要一边解释一边运行,用到哪些源代码就编译哪些源代码,整个过程由解释器完成。没有解释器的话,JavaScript 只是一堆纯文本文件,不能被计算机识别。
2) 标准库
我们在 JavaScript 代码中会调用一些内置函数,这些函数不是我们自己编写的,而是标准库自带的。
3) 本地模块
所谓本地模块,就是已经被提前编译好的模块,它们是二进制文件,和可执行文件在内部结构上没有什么区别,只是不能单独运行而已。这些本地模块其实就是动态链接库(在 Windows 下是 .dll 文件),如果你使用过C语言、C++ 等编译型语言,那你应该能够更好地理解它。

WEB自动化测试实战

JavaScript 的很多功能都需要本地模块的支持,比如:

源码软件

  • Cookie 用于存储少量的用户数据,它是用户计算机上的一种小文件,使用 Cookie 必须有文件操作模块的支持。
  • Ajax 可以借助互联网从服务器请求数据,这是一种网络操作,必须有网络库的支持。
  • 一步一步跟踪代码的执行流程,从中发现逻辑错误,这个过程叫做调试,需要有调试器(Debugger)的支持。
  • JavaScript 可以操作 HTML,这需要 HTML 解析模块提前构建起 DOM 树。

本地模块一般封装了通用功能,对性能要求较高,所以通常使用编译型语言来实现,比如C语言、C++、汇编语言等。

2021版C语言教程

JavaScript 解释器需要本地模块的支持,标准库在编写时也会调用本地模块的接口,而我们编写的 JavaScript 代码一般不会直接使用本地模块,所以 Web 前端程序员触及不到它们。

微信小程序获取地理位置

本地模块是幕后英雄,它不显山露水,但是又不可或缺。

启发式算法

总结

TCP协议

解释器、标准库、本地模块等各种组件/工具共同支撑了 JavaScript 代码的运行,它们统称为 JavaScript 运行时。

性能测试

在 Node.js 之前,JavaScript 运行时被绑定在浏览器中,作为浏览器的各种模块出现。这意味着,要想运行 JavaScript 代码就必须启动浏览器,JavaScript 逃不出浏览器的手掌心,它的功能受到很大的限制,只能作为网页脚本使用。

2. Node.js 的诞生

JavaScript 的一生伴随着浏览器大战。JavaScript 由 Netscape(网景)浏览器发布,但是 Netscape 在和 IE 的竞争中落败,早已不复存在;后来谷歌公司的 Chrome 浏览器异军突起,凭借强悍的性能把 IE 按在地上摩擦。

谷歌公司在 Chrome 浏览器中集成了一种名为“V8”的 JavaScript 引擎(也即 JavaScript 解释器),它能够非常快速地解析和执行 JavaScript 代码。

V8 引擎使用 C++ 语言编写,可以独立运行,也可以嵌入到任何其它 C++ 程序中。谷歌公司将 V8 引擎甚至整个 Chrome 浏览器都开源了,任何人都可以免费地将 V8 应用到自己的项目中。

V8 引擎的强大,以及当年 JavaScript 的火爆,使得一名叫 Ryan Dahl 的程序员动起了“歪心思”,他希望在浏览器之外再为 JavaScript 构建一个运行时,让 JavaScript 能够直接在计算机上运行,这样 JavaScript 就能像 Python、Ruby、PHP 等其它脚本语言一样大展宏图,不必再受限于浏览器,只能做一些小事情。

Ryan Dahl 和他的团队真的做到了,并且做得很好,他们将这套独立的 JavaScript 运行时命名为 Node.js;为了避免被误认为是 JavaScript 框架,现在也经常简称为 Node。
在这里插入图片描述

V8 引擎官网:https://v8.dev/

3. Node.js 的组成

Node.js 运行时主要由 V8 引擎、标准库和本地模块组成,尤其是本地模块的多少,从底层决定了 Node.js 功能的强弱。

1) V8 引擎
V8 引擎就是 JavaScript 解释器,它负责解析和执行 JavaScript 代码。

V8 引擎借鉴了 Java 虚拟机和 C++ 编译器的众多技术,它将 JavaScript 代码直接编译成原生机器码,并且使用了缓存机制来提高性能,这使得 JavaScript 的运行速度可以媲美二进制程序。

2) 本地模块
Node.js 集成了众多高性能的开源库,它们使用 C/C++ 语言实现,比如:

模块 说明
libuv 一个跨平台的、基于事件驱动的异步 I/O 库。但是 libuv 不仅限于 I/O,它还提供了进程管理、线程池、信号处理、定时器等其它功能。Linux 中一切皆文件,这里的 I/O 不仅仅包括文件读写,还包括数据库读写、网络通信(socket)等。
nmp Node.js 包管理器,可以下载包、安装包、卸载包、更新包、上传包等。
http_parser 一款由C语言编写的轻量级 HTTP 解析器,用以支持 Web 应用开发。
zlib 工业级的数据压缩/解压模块,Nodejs 借助 zlib 来创建同步、异步或者流式的压缩/解压接口。
OpenSSL 该模块提供了经过严密测试的许多加密/解密功能,现代 Web 依赖这些功能来实现安全性,比如 SSL 协议和 https 协议。
c-ares 异步 DNS 查询和解析库。

Node.js 直接在计算机上运行 JavaScript 代码,并且要赋予 JavaScript 强大的能力,所以它的本地模块和浏览器中的运行时有很多大区别,甚至说几乎没有什么关联。Node.js 几乎完全抛弃了浏览器,自己从头构建了一套全新的 JavaScript 运行时。

3) 标准库
本地模块使用 C/C++ 编写,而 Node.js 面向 JavaScript 开发人员,所以必须要封装本地模块的 C/C++ 接口,提供一套优雅的 JavaScript 接口给开发人员,并且要保持接口在不同平台(操作系统)上的一致性。

这套 JavaScript 接口,就是 Node.js 标准库。标准库是否优雅和强大,决定了 Node.js 的易用性,直接影响 Node.js 的市场表现。

总结
V8 引擎和众多本地模块都是现成的,别人已经造好了轮子,Node.js 的主要工作就是选择合适的模块,将它们集成在一起,并编写好 JavaScript 接口。

当然,并不是所有的本地模块都能找到合适的,Node.js 也自己编写了几个模块,典型的代表就是 Libuv。Libuv 是 Node.js 最核心最基础的模块,Node.js 完全基于 Libuv 而构建。

你可能听说过 Node.js 采用了基于事件的、单线程的异步 I/O 架构,这是 Node.js 最大的特点,也是它和其它脚本语言最大的区别,Node.js 的这种能力就是依赖 Libuv 实现的。

Libuv 如此强大,官方决定将它从 Node.js 中剥离出来,作为一个单独的网络库发布,并且开源免费。现在的 Libuv 已经变得非常流行,和传统的 Libevent 和 libev 库并称为“C/C++ 三大网络库”。

Node.js 之所以大名鼎鼎,主要是因为它采用了 V8 引擎和 Libuv 库:V8 引擎保证了 Node.js 运行高效,Libuv 库提供了基于事件循环的异步 I/O 能力。
在这里插入图片描述

Libuv 官网:http://libuv.org/

4. 总结

Node.js 是一个 JavaScript 运行时,它让 JavaScript 脱离了浏览器环境,可以直接在计算机上运行,极大地拓展了 JavaScript 用途。我们应该将 JavaScript 和 Python、Java、Ruby 等其它编程语言同等对待,不能再将它视为一种“小玩意”。

最后我们来汇总一下 JavaScript 和 Node.js 的历史:

  • Netscape 浏览器衍生出了 JavaScript 脚本,赋予网页编程能力;
  • Chrome 浏览器衍生了 V8 引擎,提高了 JavaScript 性能;
  • V8 引擎构建了 Node.js,拓展了 JavaScript 的编程能力;
  • Node.js 衍生了 Libuv 库,给网络开发增加了一款优秀的工具。

第一个JavaScript 程序

JavaScript 程序不能够独立运行,只能在宿主环境中执行。一般情况下可以把 JavaScript 代码放在网页中,借助浏览器环境来运行。

在 HTML 文档中嵌入 JavaScript 代码
在 HTML 页面中嵌入 JavaScript 脚本需要使用

<

s

c

r

i

p

t

>

<script>

<script>标签,用户可以在

<

s

c

r

i

p

t

>

<script>

<script> 标签中直接编写 JavaScript 代码,具体步骤如下。

第1步,新建 HTML 文档,保存为 test.html。

第2步,在 标签内插入一个

第3步,为

<

s

c

r

i

p

t

>

<script>

<script> 标签设置

t

y

p

e

=

"

t

e

x

t

/

j

a

v

a

s

c

r

i

p

t

"

type="text/javascript"

type="text/javascript"属性。

现代浏览器默认

<

s

c

r

i

p

t

>

<script>

<script> 标签的脚本类型为 JavaScript,因此可以省略 type 属性;如果考虑到兼容早期版本浏览器,则需要设置 type 属性。

第4步,在

<

s

c

r

i

p

t

>

<script>

<script> 标签内输入 JavaScript 代码

d

o

c

u

m

e

n

t

.

w

r

i

t

e

(

"

<

h

1

>

H

e

l

l

o

W

o

r

l

d

!

<

/

h

1

>

"

)

;

document.write("<h1>Hello World!</h1>");

document.write("<h1>HelloWorld!</h1>");

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>第一个JavaScript程序</title>
    <script type="text/javascript">
        document.write("<h1>Hello World!</h1>");
    </script>
</head>
<body></body>
</html>

在 JavaScript 脚本中,document 表示网页文档对象;document.write() 表示调用 Document 对象的 write() 方法,在当前网页源代码中写入 HTML 字符串

"

<

h

1

>

H

e

l

l

o

W

o

r

l

d

!

<

/

h

1

>

"

"<h1>Hello World!</h1>"

"<h1>HelloWorld!</h1>"

第5步,保存网页文档,在浏览器中预览,显示效果如图所示。
在这里插入图片描述

1. 在脚本文件中编写 JavaScript 代码

JavaScript 程序不仅可以直接放在 HTML 文档中,也可以放在 JavaScript 脚本文件中。JavaScript 脚本文件是文本文件,扩展名为.js,使用任何文本编辑器都可以编辑。

常用的文本编辑器有 Windows 系统中的记事本、Linux 系统中的 Vim、Sublime Text、Notepad++ 等。对于初学者来说,建议先使用文本编辑器来编写 JavaScript 代码,这样有助于我们对 JavaScript 语法、关键字、函数等内容的记忆。等到了实际开发阶段,则可以选择一些更加专业的代码编辑器,例如 Visual Studio Code(简称“VS Code”)、WebStorm(收费)、Atom 等,这样可以提高开发效率。

新建 JavaScript 文件的步骤如下。

第1步,新建文本文件,保存为 test.js。注意,扩展名为.js,它表示该文本文件是 JavaScript 类型的文件。

第2步,打开 test.js 文件,在其中编写如下 JavaScript 代码。

alert(“Hello World!”);

在上面代码中,alert() 表示 Window 对象的方法,调用该方法将弹出一个提示对话框,显示参数字符串 “Hello World!”。

第3步,保存 JavaScript 文件。在此建议把 JavaScript 文件和网页文件放在同一个目录下。

JavaScript 文件不能够独立运行,需要导入到网页中,通过浏览器来执行。使用

<

s

c

r

i

p

t

>

<script>

<script> 标签可以导入 JavaScript 文件。

第4步,新建 HTML 文档,保存为 test.html。

第5步,在 标签内插入一个

<

s

c

r

i

p

t

>

<script>

<script> 标签。定义 src 属性,设置属性值为指向外部 JavaScript 文件的 URL 字符串。代码如下:

<script type="text/javascript" src="test.js"></script>

注意:使用

s

c

r

i

p

t

<script>

script标签包含外部 JavaScript 文件时,默认文件类型为 Javascript。因此,不管加载的文件扩展名是不是 .js,浏览器都会按 JavaScript 脚本来解析。

第6步,保存网页文档,在浏览器中预览,显示效果如图所示。
在这里插入图片描述定义 src 属性的

<

s

c

r

i

p

t

>

<script>

<script> 标签不应再包含 JavaScript 代码。如果嵌入了代码,则只会下载并执行外部 JavaScript 文件,嵌入代码将被忽略。

2. JavaScript 代码执行顺序

浏览器在解析 HTML 文档时,将根据文档流从上到下逐行解析和显示。JavaScript 代码也是 HTML 文档的组成部分,因此 JavaScript 脚本的执行顺序也是根据

<

s

c

r

i

p

t

>

<script>

<script> 标签的位置来确定的。

示例

使用浏览器测试下面示例,会看到 JavaScript 代码从上到下逐步被解析的过程。

<!DOCTYPE html>
<script>
    alert("顶部脚本");
</script>
<html>
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <script>
        alert("头部脚本");
    </script>
</head>
<body>
    <h1>网页标题</h1>
    <script>
        alert("页面脚本");
    </script>
    <p>正文内容</p>
</body>
<script>
    alert("底部脚本");
</script>
</html>

在浏览器中浏览上面示例网页,首先弹出提示文本“顶部脚本”,然后显示网页标题“test”,接着弹出提示文本“头部脚本”,下面才显示一级标题文本“网页标题”,继续弹出提示文本“页面脚本”, 接着显示段落文本“正文内容”,最后弹出提示文本“底部脚本”。

你看,对于导入的 JavaScript 文件,也将按照

s

c

r

i

p

t

>

<script>

script> 标签在文档中出现的顺序来执行,而且执行过程是文档解析的一部分,不会单独解析或者延期执行。

如果想改变 JavaScript 文件的执行顺序,可以给

<

s

c

r

i

p

t

>

<script>

<script> 标签增加 defer 或者 async 属性,想了解的读者请转到:JS文件延迟和异步加载(defer和async属性)

JavaScript 中的几个重要概念

本文我们讲解一下 JavaScript 中的几个简单的概念,包括标识符、关键字、保留字、大小写和字面量。这些基本概念虽然不能直接提升我们的编程能力,但它们是 JavaScript 的基本组成元素。

1. 标识符

所谓标识符(Identifier),就是名字。JavaScript 中的标识符包括变量名、函数名、参数名、属性名、类名等。

合法的标识符应该注意以下强制规则:

  • 第一个字符必须是字母、下划线(_)或美元符号($)。
  • 除了第一个字符外,其他位置可以使用 Unicode 字符。一般建议仅使用 ASCII 编码的字母,不建议使用双字节的字符。
  • 不能与 JavaScript 关键字、保留字重名。
  • 可以使用 Unicode 转义序列。例如,字符 a 可以使用“\u0061”表示。

示例

在下面示例中,str 就是变量的名字:

var str = "C语言中文网:c.biancheng.net";
document.write(str);

第1行代码定义了一个变量,名字为 str,第2行通过 str 这个名字使用了变量。

2. 关键字

关键字(Keyword)就是 JavaScript 语言内部使用的一组名字(或称为命令)。这些名字具有特定的用途,用户不能自定义同名的标识符,具体说明如表所示。

JavaScript 关键字

break delete if this while
case do in throw with
catch else instanceof try
continue finally new typeof
debugger(ECMAScript 5 新增) for return var
default function switch void

3. 保留字

保留字就是 JavaScript 语言内部预备使用的一组名字(或称为命令)。这些名字目前还没有具体的用途,是为 JavaScript 升级版本预留备用的,建议用户不要使用。具体说明如表所示。

JavaScript 保留字

abstract double goto native static
boolean enum implements package super
byte export import private synchronized
char extends int protected throws
class final interface public transient
const float long short volatile

ECMAScript 3 将 Java 所有关键字都列为保留字,而 ECMAScript 5 规定较为灵活,例如:

  • 在非严格模式下,仅规定 class、const、enums、export、extends、import、super 为保留字,其他 ECMAScript 3 保留字可以自由使用;
  • 在严格模式下,ECMAScript 5 变得更加谨慎,严格限制 implements、interface、let、package、private、protected、public、static、yield、eval(非保留字)、arguments(非保留字)的使用。

JavaScript 预定义了很多全局变量和函数,用户也应该避免使用它们,具体说明如表所示。

JavaScript 预定义全局变量和函数

arguments encodeURL Infinity Number RegExp
Array encodeURLComponent isFinite Object String
Boolean Error isNaN parseFloat SyntaxError
Date eval JSON parseInt TypeError
decodeURL EvalError Math RangeError undefined
decodeURLComponent Function NaN ReferenceError URLError

不同的 JavaScript 运行环境都会预定义一些全局变量和函数,上表列出的仅针对 Web 浏览器运行环境。

无论是在严格模式下还是在非严格模式下,都不要在定义变量名、函数名或者属性名时使用上面列举出的保留字,以免同学们入坑。

4. 区分大小写

JavaScript 严格区分大小写,所以 Hello 和 hello 是两个不同的标识符。

为了避免输入混乱和语法错误,建议采用小写字符编写代码,在以下特殊情况下可以使用大写形式:

  1. 构造函数的首字母建议大写。构造函数不同于普通函数。

示例

下面示例调用预定义的构造函数 Date(),创建一个时间对象,然后把时间对象转换为字符串显示出来。

d = new Date();  //获取当前日期和时间
document.write(d.toString());  // 显示日期
  1. 如果标识符由多个单词组成,可以考虑使用骆驼命名法——除首个单词外,后面单词的首字母大写。例如:
typeOf();
printEmployeePaychecks();

提示:

上述都是约定俗成的一般习惯,不构成强制性要求,用户可以根据个人习惯进行命名。

5. 直接量

字面量(Literal)也叫直接量,就是具体的值,即能够直接参与运算或显示的值,如字符串、数值、布尔值、正则表达式、对象直接量、数组直接量、函数直接量等。

示例

下面示例分别定义不同类型的直接量:字符串、数值、布尔值、正则表达式、特殊值、对象、数组和函数。

//空字符串直接量
1  //数值直接量
true  //布尔值直接量
/a/g  //正则表达式直接量
null  //特殊值直接量
{}  //空对象直接量
[]  //空数组直接量
function(){}  //空函数直接量,也就是函数表达式

JS注释(多行注释+单行注释)

注释是给开发人员看的,程序在执行时会自动忽略注释的内容,所以我们通常使用注释来为代码添加一些解释说明或描述,以提高代码的可读性。JavaScript 中的注释与 C/C++、Java、PHP 等语言中注释的定义方式相同,支持单行注释和多行注释两种风格。

1. 单行注释

单行注释以双斜杠//开头,//之后的所有内容都会看作是注释的内容,对//之前的内容则不会产生影响,示例代码如下:

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript</title>
</head>
<body>
    <div id="demo"></div>
    <script>
        // 在 id 属性为 demo 的标签中添加指定内容
        document.getElementById("demo").innerHTML = "Hello World!";
    </script>
</body>
</html>

注意:单行注释 // 只对所在行有效。

另外,单行注释除了可以独占一行外,也可以在代码的末尾使用,如下例所示:

var x = 5;      // 声明变量 x,并把 5 赋值给它
var y = x + 2;  // 声明变量 y,并把 x+2 赋值给它

2. 多行注释

多行注释以 /* 开头,并以 */ 结尾,出现在 /**/ 之间的所有内容都会看作是注释的内容,示例代码如下:

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript</title>
</head>
<body>
    <div id="demo"></div>
    <script>
        /*
        在 id 属性为 demo 的标签中
        添加指定内容
        */
        document.getElementById("demo").innerHTML = "Hello World!";
    </script>
</body>
</html>

3. 使用注释来阻止程序执行

使用注释除了可以为代码添加解释说明或描述外,在调试代码的时候,我们也可以将不需要运行的代码注释起来,这样在运行程序时浏览器就会忽略注释中的代码。如下例所示:

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript</title>
</head>
<body>
    <div id="demo"></div>
    <script>
        document.getElementById("demo").innerHTML = "JavaScript教程";
        // document.getElementById("demo").innerHTML = "JavaScript";
        /*
            document.getElementById("demo").innerHTML = "注释";
            document.getElementById("demo").innerHTML = "JavaScript注释";
         */
    </script>
</body>
</html>

4. HTML 注释

JavaScript 还能够识别 HTML 注释的开始符 <!--,并将其看作单行注释,与 //效果相同。至于 HTML 注释的结束符 --> JavaScript 则不能识别,因此若要使用 HTML 注释来注释 JavaScript 代码,应该使用 JavaScript 的单行注释将 HTML 注释的结束符 --> 注释掉,例如 //-->。示例代码如下:

<!--document.getElementById("demo").innerHTML = "Hello World!";
// -->
// document.getElementById("demo").innerHTML = "Hello World!";

上面代码中,两种注释的效果是一样的。

JS 变量定义和赋值

变量是所有编程语言的基础之一,可以用来存储数据,例如字符串、数字、布尔值、数组等,并在需要时设置、更新或者读取变量中的内容。我们可以将变量看作一个值的符号名称。

1. 变量的命名规则

在 JavaScript 中,变量名称并不能随便定义,需要遵循标识符的命名规则,如下所示:

  • 变量名中可以包含数字、字母、下划线_、美元符号$;
  • 变量名中不能出现汉字;
  • 变量名中不能包含空格;
  • 变量名不能是 JavaScript 中的关键字、保留字;
  • 变量名不能以数字开头,即第一个字符不能为数字。

在定义变量时,变量名要尽量有意义,让自己或者他人能轻易看懂,例如可以使用 name 来定义一个存储姓名的变量、使用 dataArr 来定义一个数组类型的变量。

当变量名中包含多个英文单词时,推荐使用驼峰命名法(大驼峰:每个单词首字母大写,例如 FileType、DataArr;小驼峰:第一个单词首字母小写后面的单词首字母大写,例如 fileType、dataArr)。

提示: JavaScript 中的关键字、保留字不能作为变量的名称。

2. 定义变量

在 JavaScript 中,定义变量需要使用 var 关键字,语法格式如下:

var 变量名;

举几个例子:

var str;  //用来存储字符串
var age;  //用来存储年龄
var prePage;  //用来存储上一页

定义变量时,可以一次定义一个或多个变量,若定义多个变量,则需要在变量名之间使用逗号, 分隔开,如下例所示:

var a, b, c; // 同时声明多个变量

变量定义后,如果没有为变量赋值,那么这些变量会被赋予一个初始值——undefined(未定义)。

3. 为变量赋值

变量定义后,可以使用等于号=来为变量赋值,等号左边的为变量的名称,等号右边为要赋予变量的值,如下例所示:

var num;    // 定义一个变量 num
num = 1;    // 将变量 num 赋值为 1

此外,也可以在定义变量的同时为变量赋值,如下例所示:

var num = 1;                // 定义一个变量 num 并将其赋值为 1
var a = 2, b = 3, c = 4;    // 同时定义 a、b、c 三个变量并分别赋值为 2、3、4
// var a = 2,               // 为了让代码看起来更工整,上一行代码也可以写成这样
//     b = 3,
//     c = 4;      

4. 变量提升

JavaScript 在预编译期会先预处理声明的变量,但是变量的赋值操作发生在 JavaScript 执行期,而不是预编译期。

document.write(str); //显示undefined
str = http://c.biancheng.net/js/;
document.write(str); //显示 http://c.biancheng.net/js/
var str;

在上面示例中,声明变量放在最后,赋值操作放在前面。由于 JavaScript 在预编译期已经对变量声明语句进行了预解析,所以第1行代码读取变量值时不会抛出异常,而是返回未初始化的值 undefined。第3行代码是在赋值操作之后读取,故显示为数字 1。

JavaScript 引擎的解析方式是:先解析代码,获取所有被声明的变量,然后再一行一行地运行。 这样,所有声明的变量都会被提升到代码的头部,这就叫作变量提升(Hoisting)。

5. let 和 const 关键字

2015 年以前,JavaScript 只能通过 var 关键字来声明变量,在 ECMAScript6(ES6)发布之后,新增了 let 和 const 两个关键字来声明变量,其中:

  • 使用 let 关键字声明的变量只在其所在的代码块中有效(类似于局部变量),并且在这个代码块中,同名的变量不能重复声明;
  • const 关键字的功能和 let 相同,但使用 const 关键字声明的变量还具备另外一个特点,那就是 const 关键字定义的变量,一旦定义,就不能修改(即使用 const 关键字定义的为常量)。

注意: IE10 及以下的版本不支持 let 和 const 关键字。

示例代码如下:

let name = "小明";      // 声明一个变量 name 并赋值为“小明”
let age  = 11;          // 声明一个变量 age
let age  = 13;          // 报错:变量 age 不能重复定义
const PI = 3.1415       // 声明一个常量 PI,并赋值为 3.1415
console.log(PI)         // 在控制台打印 PI

JS 数据类型(基本数据类型+引用类型)

数据类型指的是可以在程序中存储和操作的值的类型,每种编程语言都有其支持的数据类型,不同的数据类型用来存储不同的数据,例如文本、数值、图像等。

JavaScript 是一种动态类型的语言,在定义变量时不需要提前指定变量的类型,变量的类型是在程序运行过程中由 JavaScript 引擎动态决定的,另外,您可以使用同一个变量来存储不同类型的数据,例如:

var a;  // 此时 a 为 Undefined
a = "http://c.biancheng.net/"; // 此时 a 为 String 类型
a = 123;  // 此时 a 为 Number 类型

JavaScript 中的数据类型可以分为两种类型:

  • 基本数据类型(值类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol;
  • 引用数据类型:对象(Object)、数组(Array)、函数(Function)。

提示:Symbol 是 ECMAScript6 中引入的一种新的数据类型,表示独一无二的值。

typeof 操作符

在开始介绍各种数据类型之前,先来了解一下 typeof 操作符,使用 typeof 操作符可以返回变量的数据类型。

typeof 操作符有带括号和不带括号两种用法,如下例所示:

typeof x;       // 获取变量 x 的数据类型
typeof(x);      // 获取变量 x 的数据类型

1. JS 基本数据类型

1) String 类型

字符串(String)类型是一段以单引号''或双引号""包裹起来的文本,例如 ‘123’、“abc”。需要注意的是,单引号和双引号是定义字符串的不同方式,并不是字符串的一部分。

定义字符串时,如果字符串中包含引号,可以使用反斜杠 \ 来转义字符串中的引号,或者选择与字符串中不同的引号来定义字符串,如下例所示:

var str = "Let's have a cup of coffee.";  // 双引号中包含单引号
var str = 'He said "Hello" and left.';    // 单引号中包含双引号
var str = 'We\'ll never give up.';        // 使用反斜杠转义字符串中的单引号

2) Number 类型

数值(Number)类型用来定义数值,JavaScript 中不区分整数和小数(浮点数),统一使用 Number 类型表示,如下例所示:

var num1 = 123;     // 整数
var num2 = 3.14;    // 浮点数

注意:Number 类型所能定义的数值并不是无限的,JavaScript 中的 Number 类型只能表示 -(253 – 1) 到 (253 -1) 之间的数值。

对于一些极大或者极小的数,也可以通过科学(指数)计数法来表示,如下例所示:

var y=123e5;      // 123 乘以 10 的 5 次方,即 12300000
var z=123e-5;     // 123 乘以 10 的 -5 次方,即 0.00123

另外,Number 类型中还有一些比较特殊的值,分别为 Infinity、-Infinity 和 NaN,其中

  • Infinity:用来表示正无穷大的数值,一般指大于 1.7976931348623157e+308 的数;
  • -Infinity:用来表示负无穷大的数值,一般指小于 5e-324 的数;
  • NaN:即非数值(Not a Number 的缩写),用来表示无效或未定义的数学运算结构,例如 0 除以 0。

提示:如果某次计算的结果超出了 JavaScript 中 Number 类型的取值范围,那么这个数就会自动转化为无穷大,正数为 Infinity,负数为 -Infinity。

3) Boolean 类型

布尔(Boolean)类型只有两个值,true(真)或者 false(假),在做条件判断时使用的比较多,您除了可以直接使用 true 或 false 来定义布尔类型的变量外,还可以通过一些表达式来得到布尔类型的值,例如:

var a = true;   // 定义一个布尔值 true
var b = false;  // 定义一个布尔值 false
var c = 2 > 1;  // 表达式 2 > 1 成立,其结果为“真(true)”,所以 c 的值为布尔类型的 true
var d = 2 < 1;  // 表达式 2 < 1 不成立,其结果为“假(false)”,所以 c 的值为布尔类型的 false

4) Null 类型

Null 是一个只有一个值的特殊数据类型,表示一个“空”值,即不存在任何值,什么都没有,用来定义空对象指针。

使用 typeof 操作符来查看 Null 的类型,会发现 Null 的类型为 Object,说明 Null 其实使用属于 Object(对象)的一个特殊值。因此通过将变量赋值为 Null 我们可以创建一个空的对象。

5) Undefined 类型

Undefined 也是一个只有一个值的特殊数据类型,表示未定义。当我们声明一个变量但未给变量赋值时,这个变量的默认值就是 Undefined。例如:

var num;
console.log(num);  // 输出 undefined

在使用 typeof 操作符查看未赋值的变量类型时,会发现它们的类型也是 undefined。对于未声明的变量,使用 typeof 操作符查看其类型会发现,未声明的变量也是 undefined,示例代码如下:

var message;
console.log(typeof message);  // 输出 undefined
console.log(typeof name);     // 输出 undefined

6) Symbol 类型

Symbol 是 ECMAScript6 中引入的一种新的数据类型,表示独一无二的值,Symbol 类型的值需要使用 Symbol() 函数来生成,如下例所示:

var str = "123";
var sym1 = Symbol(str);
var sym2 = Symbol(str);
console.log(sym1);          // 输出 Symbol(123)
console.log(sym2);          // 输出 Symbol(123)
console.log(sym1 == sym2);  // 输出 false :虽然 sym1 与 sym2 看起来是相同的,但实际上它们并不一样,根据 Symbol 类型的特点,sym1 和 sym2 都是独一无二的

2. JS 引用数据类型

1) Object 类型

JavaScript 中的对象(Object)类型是一组由键、值组成的无序集合,定义对象类型需要使用花括号{ },语法格式如下:

{name1: value1, name2: value2, name3: value3, …, nameN: valueN}

其中 name1、name2、name3、…、nameN 为对象中的键,value1、value2、value3、…、valueN 为对应的值。

在 JavaScript 中,对象类型的键都是字符串类型的,值则可以是任意数据类型。要获取对象中的某个值,可以使用 对象名.键 的形式,如下例所示:

var person = {
    name: 'Bob',
    age: 20,
    tags: ['js', 'web', 'mobile'],
    city: 'Beijing',
    hasCar: true,
    zipcode: null
};
console.log(person.name);       // 输出 Bob
console.log(person.age);        // 输出 20

2) Array 类型

数组(Array)是一组按顺序排列的数据的集合,数组中的每个值都称为元素,而且数组中可以包含任意类型的数据。在 JavaScript 中定义数组需要使用方括号[ ],数组中的每个元素使用逗号进行分隔,例如:

[1, 2, 3, 'hello', true, null]

另外,也可以使用 Array() 函数来创建数组,如下例所示:

var arr = new Array(1, 2, 3, 4);
console.log(arr);       // 输出 [1, 2, 3, 4]

数组中的元素可以通过索引来访问。数组中的索引从 0 开始,并依次递增,也就是说数组第一个元素的索引为 0,第二个元素的索引为 1,第三个元素的索引为 2,以此类推。如下例所示:

var arr = [1, 2, 3.14, 'Hello', null, true];
console.log(arr[0]);  // 输出索引为 0 的元素,即 1
console.log(arr[5]);  // 输出索引为 5 的元素,即 true
console.log(arr[6]);  // 索引超出了范围,返回 undefined

3) Function 类型

函数(Function)是一段具有特定功能的代码块,函数并不会自动运行,需要通过函数名调用才能运行,如下例所示:

function sayHello(name){
    return "Hello, " + name;
}
var res = sayHello("Peter");
console.log(res);  // 输出 Hello, Peter

此外,函数还可以存储在变量、对象、数组中,而且函数还可以作为参数传递给其它函数,或则从其它函数返回,如下例所示:

var fun = function(){
    console.log("http://c.biancheng.net/js/");
}
function createGreeting(name){
    return "Hello, " + name;
}
function displayGreeting(greetingFunction, userName){
    return greetingFunction(userName);
}
var result = displayGreeting(createGreeting, "Peter");
console.log(result);  // 输出 Hello, Peter

JS 运算符汇总

运算符是用来告诉 JavaScript 引擎执行某种操作的符号,例如加号(+)表示执行加法运算,减号(-)表示执行减法运算等,本节我们就来介绍一下 JavaScript 中不同的运算符。

1. 算术运算符

算数运算符用来执行常见的数学运算,例如加法、减法、乘法、除法等,下表中列举了 JavaScript 中支持的算术运算符:

在这里插入图片描述

示例代码如下:

var x = 10,
    y = 4;
console.log("x + y =", x + y);  // 输出:x + y = 14
console.log("x - y =", x - y);  // 输出:x - y = 6
console.log("x * y =", x * y);  // 输出:x * y = 40
console.log("x / y =", x / y);  // 输出:x / y = 2.5
console.log("x % y =", x % y);  // 输出:x % y = 2

上述代码中,双引号中的内容是一个字符串,所以其中的运算符会原样输出,并不参与运算。

2. 赋值运算符

赋值运算符用来为变量赋值,下表中列举了 JavaScript 中支持的赋值运算符:

在这里插入图片描述

示例代码如下:

var x = 10;
x += 20;
console.log(x);  // 输出:30
var x = 12,
    y = 7;
x -= y;
console.log(x);  // 输出:5
x = 5;
x *= 25;
console.log(x);  // 输出:125
x = 50;
x /= 10;
console.log(x);  // 输出:5
x = 100;
x %= 15;
console.log(x);  // 输出:10

3. 字符串运算符

JavaScript 中的 ++= 运算符除了可以进行数学运算外,还可以用来拼接字符串,其中:

  • + 运算符表示将运算符左右两侧的字符串拼接到一起;
  • += 运算符表示先将字符串进行拼接,然后再将结果赋值给运算符左侧的变量。

示例代码如下:

var x = "Hello ";
var y = "World!";
var z = x + y;
console.log(z);  // 输出:Hello World!
x += y;
console.log(x);  // 输出:Hello World!

4. 自增、自减运算符

自增、自减运算符用来对变量的值进行自增(+1)、自减(-1)操作,下表中列举了 JavaScript 中支持的自增、自减运算符:

在这里插入图片描述

示例代码如下:

var x;
x = 10;
console.log(++x);  // 输出:11
console.log(x);    // 输出:11
x = 10;
console.log(x++);  // 输出:10
console.log(x);    // 输出:11
x = 10;
console.log(--x);  // 输出:9
console.log(x);    // 输出:9
x = 10;
console.log(x--);  // 输出:10
console.log(x);    // 输出:9

5. 比较运算符

比较运算符用来比较运算符左右两侧的表达式,比较运算符的运算结果是一个布尔值,结果只有两种,不是 true 就是 false。下表中列举了 JavaScript 中支持的比较运算符:

在这里插入图片描述

示例代码如下:

var x = 25;
var y = 35;
var z = "25";
console.log(x == z);  // 输出: true
console.log(x === z); // 输出: false
console.log(x != y);  // 输出: true
console.log(x !== z); // 输出: true
console.log(x < y);   // 输出: true
console.log(x > y);   // 输出: false
console.log(x <= y);  // 输出: true
console.log(x >= y);  // 输出: false

6. 逻辑运算符

逻辑运算符通常用来组合多个表达式,逻辑运算符的运算结果是一个布尔值,只能有两种结果,不是 true 就是 false。下表中列举了 JavaScript 中支持的逻辑运算符:

在这里插入图片描述

示例代码如下:

var year = 2021;
// 闰年可以被 400 整除,也可以被 4 整除,但不能被 100 整除
if((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0))){
    console.log(year + " 年是闰年。");
} else{
    console.log(year + " 年是平年。");
}

7. 三元运算符

三元运算符(也被称为条件运算符),由一个问号和一个冒号组成,语法格式如下:

条件表达式 ? 表达式1 : 表达式2 ;

如果“条件表达式”的结果为真(true),则执行“表达式1”中的代码,否则就执行“表达式2”中的代码。

更多关于三元运算符的内容请转到:JS条件运算符(?:)详解

示例代码如下:

var x = 11,
    y = 20;
x > y ? console.log("x 大于 y") : console.log("x 小于 y");  // 输出:x 小于 y

条件运算符是唯一的三元运算符,其语法格式如下:

b ? x : y

b 操作数必须是一个布尔型的表达式,x 和 y 是任意类型的值。

  • 如果操作数 b 的返回值为 true,则执行 x 操作数,并返回该表达式的值。
  • 如果操作数 b 的返回值为 false,则执行 y 操作数,并返回该表达式的值。

定义变量 a,然后检测 a 是否被赋值,如果赋值则使用该值;否则设置默认值。

var a = null;  //定义变量a
typeof a != "undefined" ? a = a : a = 0;  //检测变量a是否赋值,否则设置默认值
console.log(a);  //显示变量a的值,返回null

条件运算符可以转换为条件结构:

if(typeof a != "undefined"){  //赋值
    a = a;
}else{  //没有赋值
    a = 0;
}
console.log(a);

也可以转换为逻辑表达式:

(typeof a != "undefined") && (a =a) || (a = 0);  //逻辑表达式
console.log(a);

在上面表达式中,如果 a 已赋值,则执行 (a = a) 表达式,执行完毕就不再执行逻辑或运算符后面的 (a = 0) 表达式;如果 a 未赋值,则不再执行逻辑与运算符后面的 (a = a) 表达式,转而执行逻辑或运算符后面的表达式 (a = 0)。

注意:

在实战中需要考虑假值的干扰。使用 typeof a != “undefined” 进行检测,可以避开变量赋值为 false、null、“”、NaN等假值时,也被误认为没有赋值。

8. 位运算符

位运算符用来对二进制位进行操作,JavaScript 中支持的位运算符如下表所示:
在这里插入图片描述

示例代码如下:

var a = 5 & 1,
    b = 5 | 1,
    c = 5 ^ 1,
    d = ~ 5,
    e = 5 << 1,
    f = 5 >> 1,
    g = 5 >>> 1;
console.log(a);  // 输出:1
console.log(b);  // 输出:5
console.log(c);  // 输出:4
console.log(d);  // 输出:-6
console.log(e);  // 输出:10
console.log(f);  // 输出:2
console.log(g);  // 输出:2

1) JS移位运算符

移位运算就是对二进制进行有规律低移位。移位运算可以设计很多奇妙的效果,在图形图像编程中应用广泛。

“<<”运算符

“<<”运算符执行左移位运算。在移位运算过程中,符号位始终保持不变。如果右侧空出位置,则自动填充为 0;超出 32 位的值,则自动丢弃。

把数字 5 向左移动 2 位,则返回值为 20。

console.log(5 << 2);  //返回值20

用算式进行演示,如图所示。
在这里插入图片描述

“>>”运算符

“>>”运算符执行有符号右移位运算。与左移运算操作相反,它把 32 位数字中的所有有效位整体右移,再使用符号位的值填充空位。移动过程中超出的值将被丢弃。

把数值 1000 向右移 8 位,则返回值为 3。

console.log(1000 >> 8);  //返回值3

用算式进行演示,如图所示。
在这里插入图片描述

把数值 -1000 向右移 8 位,则返回值为 -4。

console.log(-1000  >> 8);  //返回值 -4

用算式进行演示,如图所示。当符号位值为 1 时,则有效位左侧的空位全部使用 1 进行填充。
在这里插入图片描述

“>>>”运算符

“>>>”运算符执行五符号右移位运算。它把无符号的 32 位整数所有数位整体右移。对于无符号数或正数右移运算,无符号右移与有符号右移运算的结果是相同的。

下面两行表达式的返回值是相同的。

console.log(1000 >> 8);  //返回值3
console.log(1000 >> 8);  //返回值3

对于负数来说,无符号右移将使用 0 来填充所有的空位,同时会把负数作为正数来处理,所得结果会非常大所以,使用无符号右移运算符时要特别小心,避免意外错误。

console.log(-1000 >> 8);  //返回值 -4
console.log(-1000 >>> 8);  //返回值 16777212

用算式进行演示,如图所示。左侧空位不再用符号位的值来填充,而是用 0 来填充。

在这里插入图片描述

2) JS逻辑位运算符

位运算就是对二进制数执行计算,是整数的逐位运算。例如,1+1=2,在十进制计算中是正确的,但是在二进制计算中,1+1=10;对于二进制数 100 取反,等于 001,而不是 -100。

位运算符有 7 个,分为两类:

  • 逻辑位运算符:位与(&)、位或(|)、位异或(^)、非位(~)
  • 移位运算符:左移(<<)、右移(>>)、无符号右移(>>>)

逻辑位运算符与逻辑运算符的运算方式是相同的,但是针对的对象不同。逻辑位运算符针对的是二进制的整数值,而逻辑运算符针对的是非二进制的值。

“&”运算符

“&”运算符(位与)用于对两个二进制操作数逐位进行比较,并根据下表所示的换算表返回结果。

“&”运算符

第一个数的位值 第二个数的位值 运算结果
1 1 1
1 0 0
0 1 0
0 0 0

在位运算中,数值 1 表示 true,0 表示 false,反之亦然。

12 和 5 进行位与运算,则返回值为 4。

console.log(12 & 5);  //返回值4

下图以算式的形式解析了 12 和 5 进行位与运算的过程。通过位与运算,只有第 3 位的值为全为 true,故返回 true,其他位均返回 false。
在这里插入图片描述
“|”运算符

“|”运算符(位或)用于对两个二进制操作数逐位进行比较,并根据如表格所示的换算表返回结果。

“|”运算符

第一个数的位值 第二个数的位值 运算结果
1 1 1
1 0 1
0 1 1
0 0 0

12 和 5 进行位或运算,则返回值为 13。

console.log(12 | 5);  //返回值13

下图以算式的形式解析了 12 和 5 进行位或运算的过程。通过位或运算,除第 2 位的值为 false 外,其他位均返回 true。
在这里插入图片描述
“^”运算符

“^”运算符(位异或)用于对两个二进制操作数逐位进行比较,并根据如表格所示的换算表返回结果。

“^”运算符

第一个数的位值 第二个数的位值 运算结果
1 1 0
1 0 1
0 1 1
0 0 0

12 和 5 进行位异或运算,则返回值为 9。

console.log(12 ^ 5);  //返回值9

下图以算式的形式解析了 12 和 5 进行位异或运算的过程。通过位异或运算,第 1、4 位的值为 true,而第 2、3 位的值为 false。
在这里插入图片描述

“~”运算符

“~”运算符(位非)用于对一个二进制操作数逐位进行取反操作。

  • 第 1 步:把运算数转换为 32 位的二进制整数。
  • 第 2 步:逐位进行取反操作。
  • 第 3 步:把二进制反码转换为十进制浮点数。

对 12 进行位非运算,则返回值为 -13。

console.log( ~ 12 );  //返回值-13

下图以算式的形式解析了对 12 进行位非运算的过程。
在这里插入图片描述
位非运算实际上就是对数字进行取负运算,再减 1。例如:

console.log( ~ 12 == 12-1);  //返回true

JS 输出语句汇总(5种)

某些情况下,我们可能需要将程序的运行结果输出到浏览器中,JavaScript 中为我们提供了多种不同的输出语句来向浏览器中输出内容:

  1. 使用 alert() 函数来弹出提示框;
  2. 使用 confirm() 函数来弹出一个对话框;
  3. 使用 document.write() 方法将内容写入到 HTML 文档中;
  4. 使用 innerHTML 将内容写入到 HTML 标签中;
  5. 使用 console.log() 在浏览器的控制台输出内容。

接下来我们来分别介绍一下这 5 种不同的输出语句。

1. alert() 函数

使用 JS alert() 函数可以在浏览器中弹出一个提示框,在提示框中我们可以定义要输出的内容,语法格式如下:

alert(message);

其中 message 为要在提示框中输出的内容,需要注意的是,alert() 中只能输出文本内容。

alert() 函数是 window 对象下的一个函数,所以有时为了代码更严谨,我们也可以使用 window.alert() 的形式来调用 alert() 函数。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var a = 11,
            b = 5;
        window.alert("a * b = " + a * b);
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

2. confirm() 函数

JS confirm() 函数与 alert() 函数相似,它们都是 window 对象下的函数,同样可以在浏览器窗口弹出一个提示框,不同的是,使用 confirm() 函数创建的提示框中,除了包含一个“确定”按钮外,还有一个“取消”按钮。如果点击“确定”按钮,那么 confirm() 函数会返回一个布尔值 true,如果点击“取消”按钮,那么 confirm() 函数会返回一个布尔值 false。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var res = window.confirm("这里是要显示的内容");
        if(res == true){
            alert("你点击了“确定”按钮");
        }else{
            alert("你点击了“取消”按钮");
        }
    </script>
</body>
</html>

运行结果如下图所示:

在这里插入图片描述

3. console.log()

使用 JS console.log() 可以在浏览器的控制台输出信息,我们通常使用 console.log() 来调试程序,其语法格式如下:

console.log(message);

其中 message 为要输出的内容,可以是字符串或者对象类型。与 window.alert() 和 window.confirm() 可以分别简写成 alert() 和 confirm() 不同,console.log() 不能简写。

要看到 console.log() 的输出内容需要先打开浏览器的控制台。以 Chrome 浏览器为例,要打开控制台您只需要在浏览器窗口按 F12 快捷键,或者点击鼠标右键,并在弹出的菜单中选择“检查”选项即可。最后,在打开的控制台中选择“Console”选项,如下图所示:
在这里插入图片描述

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var myArr = ["Chrome","Firefox","Edge","Safari","Opera"];
        console.log(myArr);
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

4. document.write()

使用 JS document.write() 可以向 HTML 文档中写入 HTML 或者 JavaScript 代码,语法格式如下:

document.write(exp1, exp2, exp3, …);

其中 exp1、exp2、exp3 为要向文档中写入的内容,document.write() 可以接收多个参数,即我们可以一次向文档中写入多个内容,内容之间使用逗号进行分隔。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        document.write("<p>现在的时间是:</p>");
        document.write(Date());
    </script>
</body>
</html>

运行结果如下图所示:

在这里插入图片描述

5. innerHTML

与前面介绍的几个函数不同,innerHTML 是一个属性而不是一个函数,通过它可以设置或者获取指定 HTML 标签中的内容,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <div id="demo">JavaScript 输出</div>
    <script type="text/javascript">
        var demo = document.getElementById("demo");
        console.log(demo.innerHTML);
        demo.innerHTML = "<h2>innerHTML</h2>"
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

JS if else语句:条件判断语句

条件判断语句是程序开发过程中一种经常使用的语句形式,和大部分编程语言相同,JavaScript 中也有条件判断语句。所谓条件判断,指的是程序根据不同的条件来执行不同的操作,例如根据年龄来显示不同的内容,根据布尔值 true 或 false 来判断操作是成功还是失败等。

JavaScript 中支持以下几种不同形式的条件判断语句:

  • if 语句;
  • if else 语句;
  • if else if else 语句;
  • switc case 语句。

本节我们主要来介绍一下 if、if else、if else if else 语句的使用,switch case 语句会在下节为大家详细介绍。

1. if 语句

if 语句是 JavaScript 中最简单的条件判断语句,语法格式如下:

if(条件表达式){
    // 要执行的代码;
}

当条件表达式成立,即结果为布尔值 true 时,就会执行 { } 中的代码。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var age = 20;
        if(age >= 18){      // 如果 age >= 18 的结果为 true,则执行下面 { } 中的代码
            alert("adult");
        }
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

2. if else 语句

if else 语句是 if 语句的升级版,它不仅可以指定当表达式成立时要执行的代码,还可以指定当表达式不成立时要执行的代码,语法格式如下:

if(条件表达式){
    // 当表达式成立时要执行的代码
}else{
    // 当表达式不成立时要执行的代码
}

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var now = new Date();           // 获取当前的完整日期
        var dayOfWeek = now.getDay();   // 获取一个 0-6 之间的数字,用来表示当前是星期几,0 表示星期日、1 表示星期一、以此类推
        if (dayOfWeek > 0 && dayOfWeek < 6) {       // 判断:如果当前是星期一到星期五中的一天,则输出“Have a nice day!”,若不是则输出“Have a nice weekend!”
            alert("Have a nice day!");
        } else {
            alert("Have a nice weekend!");
        }
    </script>
</body>
</html>

运行结果如下图所示:

3. if else if else 语句

if 和 if else 语句都只有一个条件表达式,而 if else if else 语句是它们更高级的形式,在 if else if else 语句中允许您定义多个条件表达式,并根据表达式的结果执行相应的代码,语法格式如下:

if (条件表达式 1) {
    // 条件表达式 1 为真时执行的代码
} else if (条件表达式 2) {
    // 条件表达式 2 为真时执行的代码
}
...
  else if (条件表达式N) {
    // 条件表达式 N 为真时执行的代码
} else {
    // 所有条件表达式都为假时要执行的代码
}

提示:if else if else 语句在执行过程中,当遇到成立的条件表达式时,会立即执行其后 { } 中的代码,然后退出整个 if else if else 语句,若后续代码中还有成立的条件表达式,则不会执行。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var now = new Date();           // 获取当前的完整日期
        var dayOfWeek = now.getDay();   // 获取一个 0-6 之间的数字,用来表示当前是星期几,0 表示星期日、1 表示星期一、以此类推
        if(dayOfWeek == 0) {            // 判断当前是星期几
            alert("星期日")
        } else if(dayOfWeek == 1) {
            alert("星期一")
        } else if(dayOfWeek == 2) {
            alert("星期二")
        } else if(dayOfWeek == 3) {
            alert("星期三")
        } else if(dayOfWeek == 4) {
            alert("星期四")
        } else if(dayOfWeek == 5) {
            alert("星期五")
        } else {
            alert("星期六")
        }
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

注意事项

使用嵌套 if else 时,如果只有一行语句,也应该使用大括号包裹起来,避免条件歧义。

例如,下面嵌套 if else 就容易引发误解:

if(0)
    if(1)
        console.log(1);
else
    console.log(0);

针对上面代码,JavaScript 解释器将根据就近原则,按如下逻辑层次进行解释:

if(0)
    if(1)
        console.log(1);
    else
        console.log(0);

因此使用大括号可以避免很多问题:

if(0){
    if(1) console.log(1);
}else{
    console.log(0);
}

JS switch case语句详解

JS switch case 语句与 if else 语句的多分支结构类似,都可以根据不同的条件来执行不同的代码;但是与 if else 多分支结构相比,switch case 语句更加简洁和紧凑,执行效率更高。

JavaScript switch case 语句的语法格式如下:

switch (表达式){
    case value1:
        statements1  // 当表达式的结果等于 value1 时,则执行该代码
        break;
    case value2:
        statements2  // 当表达式的结果等于 value2 时,则执行该代码
        break;
    ......
    case valueN:
        statementsN  // 当表达式的结果等于 valueN 时,则执行该代码
        break;
    default :
        statements  // 如果没有与表达式相同的值,则执行该代码
}

switch 语句根据表达式的值,依次与 case 子句中的值进行比较:

  • 如果两者相等,则执行其后的语句段,当遇到 break 关键字时则跳出整个 switch 语句。
  • 如果不相等,则继续匹配下一个 case。
  • switch 语句包含一个可选的 default 关键字,如果在前面的 case 中没有找到相等的条件,则执行 default 后面的语句段。

注意:switch 语句中,表达式是使用全等(===)来与各个 cese 子句中的值进行匹配的。由于使用的是全等运算符,因此不会自动转换每个值的类型。

switch 语句的执行流程(工作原理)如下图所示:
在这里插入图片描述

break 关键字
switch 语句是逐行执行的,当 switch 语句找到一个与之匹配的 case 子句时,不仅会执行该子句对应的代码,还会继续向后执行,直至 switch 语句结束。为了防止这种情况产生,需要在每个 case 子句的末尾使用 break 来跳出 switch 语句。

break 除了可以用来跳出 switch 语句外,还可以用来跳出循环语句(for、for in、while、do while 等),后面我们会详细介绍。

【示例1】下面示例使用 switch case 语句设计网站登录会员管理模块。

var id = 1;
switch (id) {
    case 1 :
        console.log("普通会员");
        break;  //停止执行,跳出switch
    case 2 :
        console.log("VIP会员");
        break;  //停止执行,跳出switch
    case 3 :
        console.log("管理员");
        break;  //停止执行,跳出switch
    default :  //上述条件都不满足时,默认执行的代码
        console.log("游客");
}

1. case 子句

case 子句可以省略语句,这样当匹配时,不管下一个 case 条件是否满足,都会继续执行下一个 case 子句的语句。

【示例2】下面示例演示了把普通会员和 VIP 会员合并在一起进行检测。

var id = 1;
switch (id) {
    case 1 :
    case 2 :
        console.log("VIP会员");
        break;
    case 3 :
        console.log("管理员");
        break;
    default : 
        console.log("游客");

在 switch 语句中,case 子句只是指明了执行起点,但是没有指明执行的终点,如果在 case 子句中没有 break 语句,就会发生连续执行的情况,从而忽略后面 case 子句的条件限制,这样就容易破坏 switch 结构的逻辑。

如果在函数中使用 switch 语句,可以使用 return 语句终止 switch 语句,防止代码继续执行。

2. default语句

default 是 switch 子句,可以位于 switch 内任意位置,不会影响其它 case 子句的正常执行。下面结合示例介绍使用 default 语句应该注意 3 个问题。

【示例3】如果 default 下面还有 case 子句,应该在 default 后面添加 break 语句,终止 switch 结构,防止程序突破 case 条件的限制继续执行下面 case 子句。

var id = 1;
switch (id) {
    default : 
        console.log("游客");
        break;
    case 1 : 
        console.log("普通会员");
        break;
    case 2 :
        console.log("VIP会员");
        break;
    case 3 :
        console.log("管理员");
        break;
}

【示例4】在下面代码中,JavaScript 先检测 case 表达式的值,由于 case 表达式的值都不匹配,则跳转到 default 子句执行,然后继续执行 case 1 和 case 2 子句。但是,最后不会返回 default 子句再重复执行。

var id = 3;
switch (id) {
    default : 
        console.log("游客");
    case 1 :
        console.log("普通会员");
    case 2 :
        console.log("VIP会员");
}

【示例5】下面示例使用 switch 语句设计一个四则运算函数。在 switch 结构内,先使用 case 枚举 4 种可预知的算术运算,当然还可以继续扩展 case 子句,枚举所有可能的操作,但是无法枚举所有不测,因此最后使用 default 处理意外情况。

function oper (a,b,opr) {
    switch (opr) {
        case "+" :  //正常枚举
            return a + b;
        case "-" :  //正常枚举
            return a - b;
        case "*" :  //正常枚举
            return a * b;
        case "/" :  //正常枚举
            return a / b;
        default :  //异常处理
            return "非预期的 opr 值";
    }
}
console.log(oper (2,5,"*"));  //返回10

default 语句与 case 语句简单比较如下:

  • 语义不同:default 为默认项,case 为判例。
  • 功能扩展:default 选项是唯一的,不可以扩展。而 case 选项是可扩展的,没有限制。
  • 异常处理:default 与 case 扮演的角色不同,case 用于枚举,default 用于异常处理。

JS while循环语句的用法

循环就是重复做一件事,在编写代码的过程中,我们经常会遇到一些需要反复执行的操作,例如遍历一些数据、重复输出某个字符串等,如果一行行的写那就太麻烦了,对于这种重复的操作,我们应该选择使用循环来完成。

循环的目的就是为了反复执某段代码,使用循环可以减轻编程压力,避免代码冗余,提高开发效率,方便后期维护。while 循环是 JavaScript 中提供的最简单的循环语句,本节我们就来简单介绍一下 while 循环的使用。

1. JS while 循环语法

JS while 循环的语法格式如下:

while (条件表达式) {
    // 要执行的代码
}

while 循环在每次循环之前,会先对条件表达式进行求值,如果条件表达式的结果为 true,则执行 { } 中的代码,如果条件表达式的结果为 false,则退出 while 循环,执行 while 循环之后的代码。

while 循环的执行流程如下图所示:

在这里插入图片描述

示例代码如下:

var i = 1;
while( i <= 5) {
    document.write(i+", ");
    i++;
}

运行结果:
1, 2, 3, 4, 5,

注意事项

在编写循环语句时,一定要确保条件表达式的结果能够为假(即布尔值 false),因为只要表达式的结果为 true,循环会一直持续下去,不会自动停止,对于这种无法自动停止的循环,我们通常将其称为“无限循环”或“死循环”。

如果不小心造成无限循环,可能会导致浏览器或者计算机卡死。

2. JS while 循环示例

【示例1】使用 while 循环计算 1~100 之间所有整数的和:

var i=1;
var sum=0;
while (i <= 100){
    sum += i;
    i++;
}
document.write("1 + 2 + 3 + ... + 98 + 99 + 100 = " + sum)

运行结果:
1 + 2 + 3 + … + 98 + 99 + 100 = 5050

【示例2】找出 1900 年到 2020 年之间所有的闰年,并以每行 6 个进行输出:

var i = 1900;
var count = 0; //计数闰年的个数
while (i <= 2020) {
    //判断是否是闰年
    if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {
        document.write(i + "&nbsp;&nbsp;");
        count++;
        if (count % 6 == 0) {
            document.write("<br/>");
        }
    }
    i++;
}

运行结果:

1904 1908 1912 1916 1920 1924
1928 1932 1936 1940 1944 1948
1952 1956 1960 1964 1968 1972
1976 1980 1984 1988 1992 1996
2000 2004 2008 2012 2016 2020

JS do while循环语句的用法

JS do while 循环与 while 循环非常相似,不同之处在于,do while 循环会先执行循环中的代码,然后再对条件表达式进行判断。因此,无论条件表达式是真还是假,do while 循环都能至少执行一次,而 while 循环就不行了,如果条件表达式为假会直接退出 while 循环。

JS do while 循环语法

JS do while 循环的语法格式如下:

do {
    // 需要执行的代码
} while (条件表达式);

提示:do while 循环与 while 循环还有一点不同,那就是 do while 循环的末尾需要使用分号; 进行结尾,而 while 循环则不需要。

do while 循环的执行流程如下图所示:
在这里插入图片描述

示例代码如下:

var i = 1;
do{
    document.write(i + " ");
    i++;
}while (i > 5);

运行结果:
1

JS do while 循环示例

使用 do while 循环计算 1~100 之间所有整数的和:

var i=1;
var sum=0;
do {
    sum += i;
    i++;
} while (i <= 100);
document.write("1 + 2 + 3 + ... + 98 + 99 + 100 = " + sum)

运行结果:
1 + 2 + 3 + … + 98 + 99 + 100 = 5050

JS for循环语句的用法

前面我们简单介绍了 while 循环和 do while 循环,本节再来介绍另外一种循环——for 循环。

1. JS for 循环语法

JS for 循环适合在已知循环次数时使用,语法格式如下:

for(initialization; condition; increment) {
    // 要执行的代码
}

for 循环中包含三个可选的表达式 initialization、condition 和 increment,其中:

  • initialization:为一个表达式或者变量声明,我们通常将该步骤称为“初始化计数器变量”,在循环过程中只会执行一次;
  • condition:为一个条件表达式,与 while 循环中的条件表达式功能相同,通常用来与计数器的值进行比较,以确定是否进行循环,通过该表达式可以设置循环的次数;
  • increment:为一个表达式,用来在每次循环结束后更新(递增或递减)计数器的值。

示例代码如下:

for (var i = 1; i <= 10; i++) {
    document.write(i + " ");
}

运行结果:
1 2 3 4 5 6 7 8 9 10

上面的代码中,在循环开始之前会先执行 var i = 1; ,并将变量 i 作为计数器;然后判断 i <= 10 是否成立,如果成立则执行 { } 中的代码,如果失败则退出 for 循环;在每次循环执行完成后,执行 i++ 操作,即更新计数器的值。

【示例】使用 for 循环遍历数组中的内容:

var fruits = ["Apple", "Banana", "Mango", "Orange", "Papaya"];
for(var i = 0; i < fruits.length; i++) {
    document.write(fruits[i] + "&emsp;");
}

运行结果:
Apple Banana Mango Orange Papaya

2. JS for 循环中的三个表达式

JS for 循环中括号中的三个表达式是可以省略的,但是用于分隔三个表达式的分号不能省略,如下例所示:

// 省略第一个表达式
var i = 0;
for (; i < 5; i++) {
    // 要执行的代码
}
// 省略第二个表达式
for (var y = 0; ; y++) {
    if(y > 5){
        break;
    }
    // 要执行的代码
}
// 省略第一个和第三个表达式
var j = 0;
for (; j < 5;) {
    // 要执行的代码
    j++;
}
// 省略所有表达式
var z = 0;
for (;;) {
    if(z > 5){
        break;
    }
    // 要执行的代码
    z++;
}

3. JS for 循环嵌套

无论是哪种循环,都可以嵌套使用(即在一个循环中再定义一个或多个循环),下面就以 for 循环为例,来演示一下循环的嵌套使用:

for (var i = 1; i <= 9; i++) {
    for (var j = 1; j <= i; j++) {
        document.write(j + " x " + i + " = " + (i * j) + "&emsp;");
    }
    document.write("<br>");
}

运行结果:

1 x 1 = 1 
1 x 2 = 2 2 x 2 = 4 
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9 
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16 
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25 
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36 
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7 = 49 
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48 7 x 8 = 56 8 x 8 = 64 
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81

4. for 循环变体

为了更加方便地遍历对象、数组、字符串等内容,JS 还支持两种 for 循环变体,分别是 for in 循环和 for of 循环。

1) for in循环语句的用法

JS for in 循环是一种特殊类型的循环,也是普通 for 循环的变体,主要用来遍历对象,使用它可以将对象中的属性依次循环出来,其语法格式如下:

for (variable in object) {
    // 要执行的代码
}

其中,variable 为一个变量,每次循环时这个变量都会被赋予不同的值,我们可以在 { } 中使用这个变量来进行一系列操作;object 为要遍历的对象,在每次循环中,会将 object 对象中的一个属性的键赋值给变量 variable,直到对象中的所有属性都遍历完。

JS for in 循环示例代码:

// 定义一个对象
var person = {"name": "Clark", "surname": "Kent", "age": "36"};
// 遍历对象中的所有属性
for(var prop in person) {
    document.write("<p>" + prop + " = " + person[prop] + "</p>");
}

运行结果:

name = Clark
surname = Kent
age = 36

注意,JS for in 循环是为遍历对象而创建的,虽然也可以遍历数组,但是并不推荐,若要遍历数组,可以使用 for 循环或者 for of 循环,有关 for of 循环我们会在下节进行介绍。

2) for of循环语句的用法

JS for of 循环是 ECMAScript6 中新添加的一个循环方式,与 for in 循环类似,也是普通 for 循环的一种变体。使用 for of 循环可以轻松的遍历数组或者其它可遍历的对象,例如字符串、对象等。

JS for of 循环的语法格式如下:

for (variable of iterable) {
    // 要执行的代码
}

其中,variable 为一个变量,每次循环时这个变量都会被赋予不同的值,我们可以在后面的 { } 中使用这个变量来进行一系列操作;iterable 为要遍历的内容,在每次循环中,会将 iterable 中的一个值赋值给变量 variable,直到 iterable 中的所有值都遍历完。

示例代码如下:

// 定义一个数组
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
// 使用 for of 循环遍历数组中的每个元素
for (var value of arr) {
    document.write(value + ", ");
}
document.write("<br>");
// 定义一个字符串
var str = "Hello World!";
// 使用 for of 循环遍历字符串中的每个字符
for (var value of str) {
    document.write(value + ", ");
}
document.write("<br>");
// 定义一个对象
var obj = {"name": "Clark", "surname": "Kent", "age": "36"};
// 使用 for of 循环遍历对象中的所有属性
for(var value in obj) {
    document.write(value + ", ");
}

运行结果:

a, b, c, d, e, f,
H, e, l, l, o, , W, o, r, l, d, !,
name, surname, age,

注意: 虽然 for of 循环也可以遍历对象,但并不推荐,若要遍历对象可以使用 for in 循环。

JS break和continue语句:跳出循环

通过前面对循环的学习我们知道,默认情况下循环会在表达式结果为假时自动退出循环,否则循环会一直持续下去。某些情况下,我们不用等待循环自动退出,可以主动退出循环,JavaScript 中提供了 break 和 continue 两个语句来实现退出循环和退出(跳过)当前循环,下面我们就来详细介绍一下。

1. JS break 语句

在学习《JS switch case语句》时我们已经简单了解过了 break 语句,使用 break 语句可以跳出 switch 语句。其实使用 break 语句还可以用来跳出循环,让程序继续执行循环之后的代码(如果有的话)。

【示例】使用 break 语句跳出 for 循环:

for (var i = 0; i < 10; i++) {
    if(i == 5) {
        break;
    }
    document.write("i = " + i + "<br>");
}
document.write("循环之外的代码");

运行结果:

i = 0
i = 1
i = 2
i = 3
i = 4
循环之外的代码

2. JS continue 语句

continue 语句用来跳过本次循环,执行下次循环。当遇到 continue 语句时,程序会立即重新检测条件表达式,如果表达式结果为真则开始下次循环,如果表达式结果为假则退出循环。

break 语句用来跳出整个循环,执行循环后面的代码;continue 语句用来跳过当次循环,继续执行下次循环。

【示例】使用 continue 语句跳出 for 循环:

for (var i = 0; i < 10; i++) {
    if(i % 2 == 0) {
        continue;
    }
    document.write(i + "&nbsp;");
}

运行结果:

1 3 5 7 9

3. JavaScript 标签

从 JavaScript 1.2 开始,可以将标签与 break 和 continue 结合使用,来更精确的控制程序的执行。

JavaScript 中的标签与 HTML 中的标签不同,JavaScript 中的标签就是一个标识符(类似变量名),后面跟随一个冒号 :。JavaScript 标签可以声明在任何语句或者代码块之前,并与 break 或 continue 配合来跳出特定的循环,例如当多个循环嵌套使用时,单纯使用 break 只能跳出当前的循环,无法跳出外层循环,如果将 break 与标签配合使用,则可以一次跳出多层循环。

示例代码如下:

document.write("开始循环!<br /> ");
outerloop:          // 定义一个标签    
for (var i = 0; i < 5; i++) {
   document.write("外层循环: " + i + "<br />");
   innerloop:       // 定义一个标签
   for (var j = 0; j < 5; j++) {
      if (j > 3 ) break ;           // 跳出内层循环
      if (i == 2) break innerloop;  // 跳出内层讯息
      if (i == 4) break outerloop;  // 跳出外层循环
      document.write("内层循环: " + j + " <br />");
   }
}      
document.write("循环结束!<br /> ");

运行结果:

开始循环!
外层循环: 0
内层循环: 0
内层循环: 1
内层循环: 2
内层循环: 3
外层循环: 1
内层循环: 0
内层循环: 1
内层循环: 2
内层循环: 3
外层循环: 2
外层循环: 3
内层循环: 0
内层循环: 1
内层循环: 2
内层循环: 3
外层循环: 4
循环结束!

注意: break 或 continue 与标签之间不能出现换行。另外,标签名称和相关循环之间不能出现其它代码。

JS 函数(function)的定义和使用

函数是一组执行特定任务(具有特定功能)的,可以重复使用的代码块,前面几节中用到的 alert()、write() 就是 JavaScript 中内置的函数。

除了使用内置函数外,我们也可以自行创建函数(自定义函数),然后在需要的地方调用这个函数,这样不仅可以避免编写重复的代码,还有利于代码的后期维护。本节我们主要来介绍一下如何使用 JavaScript 编写一个自己的函数。

1. JS 定义函数

JS 函数声明需要以 function 关键字开头,之后为要创建的函数名称,function 关键字与函数名称之间使用空格分开,函数名之后为一个括号( ),括号中用来定义函数中要使用的参数(多个参数之间使用逗号,分隔开),一个函数最多可以有 255 个参数,最后为一个花括号{ },花括号中用来定义函数的函数体(即实现函数的代码),如下所示:

function functionName(parameter_list) {
    // 函数中的代码
}

示例代码如下:

function sayHello(name){
    document.write("Hello " + name);
}

上面示例中定义了一个函数 sayHello(),该函数需要接收一个参数 name,调用该函数会在页面中输出“Hello …”。

2. JS 调用函数

一旦定义好了一个函数,我们就可以在当前文档的任意位置来调用它。调用函数非常简单,只需要函数名后面加上一个括号即可,例如 alert()、write()。注意,如果在定义函数时函数名后面的括号中指定了参数,那么在调用函数时也需要在括号中提供对应的参数。

示例代码如下:

function sayHello(name){
    document.write("Hello " + name);
}
// 调用 sayHello() 函数
sayHello('C语言中文网');

提示: JavaScript 对于大小写敏感,所以在定义函数时 function 关键字一定要使用小写,而且调用函数时必须使用与声明时相同的大小写来调用函数。

3. 参数的默认值

在定义函数时,您可以为函数的参数设置一个默认值,这样当我们在调用这个函数时,如果没有提供参数,就会使用这个默认值作为参数值,如下例所示:

function sayHello(name = "World"){
    document.write("Hello " + name);
}
sayHello();                 // 输出:Hello World
sayHello('c.biancheng.net');     // 输出:Hello c.biancheng.net

4. JS 函数返回值

在函数中可以使用 return 语句将一个值(函数的运行结果)返回给调用函数的程序,这个值可以是任何类型,例如数组、对象、字符串等。对于有返回值的函数,我们可以会使用一个变量来接收这个函数的返回值,示例代码如下:

function getSum(num1, num2){
    return num1 + num2;
}
var sum1 = getSum(7, 12);      // 函数返回值为:19
var sum2 = getSum(-5, 33);     // 函数返回值为:28

提示: return 语句通常在函数的末尾定义,当函数运行到 return 语句时会立即停止运行,并返回到调用函数的地方继续执行。

另外,一个函数只能有一个返回值,若要返回多个值则,则可以将值放入一个数组中,然后返回这个数组即可,如下例所示:

function division(dividend, divisor){
    var quotient = dividend / divisor;
    var arr = [dividend, divisor, quotient]
    return arr;
}
var res = division(100, 4)
document.write(res[0]);         // 输出:100
document.write(res[1]);         // 输出:4
document.write(res[2]);         // 输出:25

5. JS 函数表达式

函数表达式与声明变量非常相似,是另外一种声明函数的形式,语法格式如下:

var myfunction = function name(parameter_list){
    // 函数中的代码
};

参数说明如下:

  • myfunction:变量名,可以通过它来调用等号之后的函数;
  • name:函数名,可以省略(一般情况下我们也会将其省略),如果省略那么该函数就会成为一个匿名函数;
  • parameter_list:为参数列表,一个函数最多可以有 255 个参数。

示例代码如下:

// 函数声明
function getSum(num1, num2) {
    var total = num1 + num2;
    return total;
}
// 函数表达式
var getSum = function(num1, num2) {
    var total = num1 + num2;
    return total;
};

上面示例中的两个函数是等价的,它们的功能、返回值、调用方法都是相同的。

注意: 在函数声明中,不需要在右花括号后放置分号,但若使用函数表达式就应该在表达式的最后以分号结尾。

函数声明和函数表达式虽然看起来非常相似,但它们的运行方式是不同的,如下例所示:

declaration();          // 输出: function declaration
function declaration() {
    document.write("function declaration");
}
expression();           // 报错:Uncaught TypeError: undefined is not a function
var expression = function() {
    document.write("function expression");
};

如上例所示,如果函数表达式在定义之前被调用,会抛出异常(报错),但函数声明则可以成功运行。这是因为在程序执行前,JavaScript 会先对函数声明进行解析,因此无论是在函数声明前还是声明后调用函数都是可行的。而函数表达式则是将一个匿名函数赋值给一个变量,所以在程序还没有执行到该表达式之前,相当于函数还未定义,因此无法调用。

JS 事件(event)处理

JS 事件(event)是当用户与网页进行交互时发生的事情,例如单机某个链接或按钮、在文本框中输入文本、按下键盘上的某个按键、移动鼠标等等。当事件发生时,您可以使用 JavaScript 中的事件处理程序(也可称为事件监听器)来检测并执行某些特定的程序。

一般情况下事件的名称都是以单词on开头的,例如点击事件 onclick、页面加载事件 onload 等。下表中列举了一些 JavaScript 中常用的事件:
在这里插入图片描述

1. 事件绑定

事件只有与 HTML 元素绑定之后才能被触发,为 HTML 元素绑定事件处理程序的方法由很多,最简单的就是通过 HTML 事件属性来直接绑定事件处理程序,例如 onclick、onmouseover、onmouseout 等属性。

以 onclick 属性为例,通过该属性我们可以为指定的 HTML 元素定义鼠标点击事件(即在该元素上单击鼠标左键时触发的事件),示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <button type="button" onclick="myBtn()">按钮</button>
    <script type="text/javascript">
        function myBtn(){
            alert("Hello World!");
        }
    </script>
</body>
</html>

除了上述方法外,我们也可以直接使用 JavaScript 中提供的内置函数来为指定元素绑定事件处理程序,如下例所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <button type="button" id="myBtn">按钮</button>
    <script>
        function sayHello() {
            alert('Hello World!');
        }
        document.getElementById("myBtn").onclick = sayHello;
    </script>
</body>
</html>

2. JS 事件示例

一般情况下,事件可以分为四大类——鼠标事件、键盘事件、表单事件和窗口事件,另外还有一些其它事件。下面通过几个示例来简单介绍一些比较常用的事件。
1) onmouseover 事件
onmouseover 事件就是指当用户鼠标指针移动到元素上时触发的事件,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <button type="button" onmouseover="alert('您的鼠标已经移动到了该按钮上');">请将鼠标移动至此处</button><br>
    <a href="#" onmouseover="myEvent()">请将鼠标移动至此处</a>
    <script>
        function myEvent() {
            alert('您的鼠标已经移动到了该链接上');
        }
    </script>
</body>
</html>

2) onmouseout 事件
onmouseout 事件与 onmouseover 事件正好相反,onmouseout 事件会在鼠标从元素上离开时触发,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <div style="width: 350px; height: 200px; border:1px solid black" id="myBox"></div>
    <script>
        function myEvent() {
            alert('您的鼠标已经离开指定元素');
        }
        document.getElementById("myBox").onmouseout = myEvent;
    </script>
</body>
</html>

3) onkeydown 事件
onkeydown 事件是指当用户按下键盘上的某个按键时触发的事件,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <input type="text" onkeydown="myEvent()">
    <script>
        function myEvent() {
            alert("您按下了键盘上的某个按钮");
        }
    </script>
</body>
</html>

4) onkeyup 事件
onkeyup 事件是指当用户按下键盘上的某个按键并将其释放(即按下并松开某个按键)时触发的事件,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <input type="text" onkeyup="myEvent()">
    <script>
        function myEvent() {
            alert("您按下了键盘上的某个按钮,并将其释放了");
        }
    </script>
</body>
</html>

JS 作用域

在 JavaScript 中,您可以在任意位置声明变量,但不同的位置会影响变量的可用范围,这个范围称为作用域。作用域可以大致分为两种类型,分别是全局作用域和局部作用域。下面就来分别介绍一下。

1. JS 全局作用域

全局作用域是指变量可以在当前脚本的任意位置访问,拥有全局作用域的变量也被称为“全局变量”,一般情况下拥有以下特征的变量具有全局作用域:

  • 最外层的函数和在最外层函数外面定义的变量拥有全局作用域;
  • 所有未定义直接赋值的变量拥有全局作用域;
  • 所有 window 对象的属性拥有全局作用域,例如 window.name、window.location、window.top 等。

示例代码如下:

var str = "Hello World!";
function myFun(){
    document.write(str);    // 输出:Hello World!
}
myFun();
document.write(str);        // 输出:Hello World!

实际情况下,所有具有全局作用域的变量都会被绑定到 window 对象中,成为 window 对象的一个属性,如下例所示:

var str = "JavaScript";
document.write(str);                    // 输出:JavaScript
document.write(window.str);             // 输出:JavaScript
document.write(str === window.str);     // 输出:true

2. JS 局部作用域

在函数内部声明的变量具有局部作用域,拥有局部作用域的变量也被称为“局部变量”,局部变量只能在其作用域中(函数内部)使用。示例代码如下:

function myFun(){
    var str = "Hello World!";
    document.write(str);    // 输出:Hello World!
}
document.write(str);        // 报错:str is not defined

在函数内定义的局部变量只有在函数被调用时才会生成,当函数执行完毕后会被立即销毁。

JS 对象的创建和使用

JavaScript 是一种面向对象的编程语言,在 JavaScript 中几乎所有的东西都是对象。因此,要想有效的使用 JavaScript,首先需要了解对象的工作原理以及如何创建并使用对象。

我们可以将对象看作是一个属性的无序集合,每个属性都有一个名称和值(键/值对)。通过《JS数据类型》一节我们知道,数组是值的集合,每个值都有一个数字索引(从零开始,依次递增)。对象类似与数组,不同的是对象中的索引是自定义的,例如 name(姓名)、age(年龄)、gender(性别)等。

1. JS 创建对象

您可以使用花括号 { } 来创建对象,{ } 中用来定义对象中的属性。属性是一个个键:值 对的组合,其中键(属性名称)始终是字符串类型的,而值(属性值)则可以是任意类型,例如字符串、数组、函数或其它对象等。不同的属性之间使用逗号进行分隔。示例代码如下:

var person = {
    name: "Peter",
    age: 28,
    gender: "Male",
    displayName: function() {
        document.write(this.name);
    }
};

提示:在对象中定义的函数通常被称为方法。

上面示例中创建了一个名为 person 的对象,该对象中包含三个属性 name、age、gender 和一个方法 displayName()。displayName() 方法中的 this.name 表示访问当前对象中的 name 属性,会被 JavaScript 解析为 person.name。

在定义对象时,属性名称虽然是字符串类型,但通常不需要使用引号来定义,但是以下三种情况则需要为属性名添加引号:

  • 属性名为 JavaScript 中的保留字;
  • 属性名中包含空格或特殊字符(除字母、数字、_ 和 $ 以外的任何字符);
  • 属性名以数字开头。

示例代码如下:

var person = {
    "first name": "Peter",
    "current age": 28,
    gender: "Male"
};

2. 访问对象的属性

要访问或获取属性的值,您可以使用 对象名.属性名 或者 对象名["属性名"] 的形式,如下例所示:

var person = {
    name: "Peter",
    age: 28,
    gender: "Male",
    displayName: function() {
        document.write(this.name);
    }
}
document.write("姓名:" + person.name + "<br>");   // 输出:姓名:Peter
document.write("年龄:" + person["age"]);          // 输出:年龄:28

在访问对象属性时,使用 对象名.属性名 的形式更易于代码的编写,但并不是所有情况下都可以使用。如果属性名中包含空格或者特殊字符,则不能使用 对象名.属性名 的形式来访问对象属性,必须使用 对象名["属性名"] 的形式才行,如下例所示:

var person = {
    "first name": "Peter",
    "current age": 28,
    gender: "Male"
};
document.write(person["first name"]);   // 输出:Peter
document.write(person.current age);     // 报错:missing ) after argument list

使用 对象名["属性名"] 的形式访问对象属性相对比较灵活,您除了可以直接通过属性名访问属性外,还可以将属性名称赋值给变量,然后再通过这个变量来访问属性的值,如下所示:

var person = {
    name: "Peter",
    age: 28,
    gender: "Male"
};
var key = "age";
document.write(person[key]); // 输出:28

3. 设置修改对象的属性

使用 对象名.属性名 或者 对象名["属性名"] 的形式除了可以获取对象的属性值外,也可以用来设置或修改对象的属性值,如下例所示:

var person = {
    name: "Peter",
    age: 28,
    gender: "Male"
};
person.phone = "15012345678";
person.age = 20;
person["name"] = "Peter Parker";
for (var key in person) {
    document.write(key + ":" + person[key] + "<br>")
}

输出结果如下所示:

name:Peter Parker
age:20
gender:Male
phone:15012345678

4. JS 删除对象的属性

您可以使用 delete 语句来删除对象中的属性,如下例所示:

var person = {
    name: "Peter",
    age: 28,
    gender: "Male",
    phone: "15012345678"
};
delete person.gender;
delete person["phone"];
for (var key in person) {
    document.write(key + ":" + person[key] + "<br>")
}

输出结果如下所示:

name:Peter
age:28

提示:delete 语句是从对象中删除指定属性的唯一方式,而将属性值设置为 undefined 或 null 仅会更改属性的值,并不会将其从对象中删除。

5. JS 调用对象的方法

您可以像访问对象中属性那样来调用对象中的方法,如下例所示:

var person = {
    name: "Peter",
    age: 28,
    gender: "Male",
    displayName: function() {
        document.write(this.name);
    }
};
person.displayName();       // 输出:Peter
person["displayName"]();    // 输出:Peter

JS Number(数字)对象

在 JavaScript 中您可以使用十进制、十六进制或八进制表示法来表示整数或浮点数。与其它编程语言不同,JavaScript 中的数字并不区分整数和浮点数,统一使用 IEEE754 标准(二进制浮点数算术标准)的 64 位浮点格式表示数字,能表示的最大值(Number.MAX_VALUE)为 ±1.7976931348623157e+308,最小值(Number.MIN_VALUE)为 ±5e-324。示例代码如下:

var x = 123;    // 整数
var y = 3.14;   // 浮点数
var z = 0xff;   // 十六进制数:255

对于比较大的数字可以使用指数表示法来表示,例如 6.02e+23 等于 6.02 x 10²³,示例代码如下:

var x = 1.57e4;     // 等于 15700
var y = 4.25e+6;    // 等于 4250000
var z = 4.25e-6;    // 等于 0.00000425

提示:JavaScript 中能够表示的最大的整数是 2⁵³ – 1,即 9007199254740991,能够表示的最小整数是 -(2⁵³ – 1),即 -9007199254740991。

除了可以使用十进制表示数字外,您也可以使用八进制或十六进制表示法来表示数字,其中八进制表示法使用 0 作为前缀,十六进制表示法使用 0x 作为前缀,示例代码如下:

var a = 0377;     // 等于 255
var b = 0123;     // 等于 83
var c = 0xff;     // 等于 255
var d = 0xb4;     // 等于 180

注意:整数可以用十进制、十六进制和八进制表示法表示,浮点数可以用十进制或指数表示法表示。

1. ±Infinity(无穷)

Infinity 是一个特殊的值,表示无穷大。当一个表达式的运算结果超过了 JavaScript 所能表示的数字上限或下限时,JavaScript 就会使用 Infinity 或 -Infinity 表示这个结果,其中 Infinity 表示正无穷大,-Infinity 表示负无穷大。示例代码如下:

var a = 5 / 0;      // 等于 Infinity
var b = -5 / 0;     // 等于 -Infinity

2. NaN(非数字)

NaN 同样是 JavaScript 中的一个特殊值,用来表示某个值不是数字。NaN 不等于(通过

=

=

!

=

=

=

=

!

=

=

=

==、!=、===、!===

==!====!=== 比较)其它任何值(包括另外一个 NaN 值),使用 isNaN() 函数可以判断一个数是否为 NaN。

以下几种操作会返回 NaN:

  • 使用函数无法将参数转换为数字时会返回 NaN,例如 parseInt(“abc”)、new Number(“abc”);
  • 结果不是实数的数学运算,例如 Math.sqrt(-1);
  • 任何操作数中包含 NaN 的表达式,例如 5 * NaN;
  • 涉及字符串的非加法运算,且字符串无法自动转换为数字,例如 “foo” / 5。

3. Number 对象

Number 对象是原始数值的包装对象,创建 Number 对象的语法格式如下:

  • var myNum = new Number(value);
  • var myNum = Number(value);

其中 value 为要创建的 Number 对象的数值,若 value 为一个非数字的值,则会尝试将其转换为数字,若转换失败则会返回 NaN。

当 Number() 函数和 new 运算符一起使用时,会创建一个新的 Number 对象。如果不用 new 运算符,把 Number() 当作一个函数来调用,则会将其中的参数转换为一个数值,并且返回这个值(如果转换失败,则返回 NaN)。

示例代码如下:

var a = new Number("123");
var b = Number("456");
var c = 789;
var d = new Number("abc");
document.write(typeof a + "<br>");      // 输出:object
document.write(typeof b + "<br>");      // 输出:number
document.write(typeof c + "<br>");      // 输出:number
document.write(d + "<br>");             // 输出:NaN

4. Number 属性

Number 对象中提供了一些属性,如下表所示:

属性 描述
Number.MAX_VALUE JavaScript 中所能表示的最大值
Number.MIN_VALUE JavaScript 中所能表示的最小值
Number.NaN 非数字
Number.NEGATIVE_INFINITY 负无穷,在溢出时返回
Number.POSITIVE_INFINITY 正无穷,在溢出时返回
Number.EPSILON 表示 1 与 Number 所能表示的大于 1 的最小浮点数之间的差
Number.MIN_SAFE_INTEGER 最小安全整数,即 -9007199254740991
Number.MAX_SAFE_INTEGER 最大安全整数,即 9007199254740991

5. Number 方法

除了属性外,Number 对象中还提供了一些方法,如下表所示:

方法 描述
Number.parseFloat() 将字符串转换成浮点数,和全局方法 parseFloat() 作用相同
Number.parseInt() 将字符串转换成整型数字,和全局方法 parseInt() 作用相同
Number.isFinite() 判断 Number 对象是否为有穷数
Number.isInteger() 判断 Number 对象是否为整数
Number.isNaN() 判断 Number 对象是否为 NaN 类型
Number.isSafeInteger() 判断 Number 对象是否为安全整数,即范围为 -(2⁵³ – 1)到 2⁵³ – 1 之间的整数
Number.toString() 把 Number 对象转换为字符串,使用指定的基数
Number.toLocaleString() 把 Number 对象转换为字符串,使用本地数字格式顺序
Number.toFixed() 把 Number 对象转换为字符串,结果的小数点后有指定位数的数字
Number.toExponential() 把 Number 对象的值转换为指数计数法
Number.toPrecision() 把 Number 对象格式化为指定的长度
Number.valueOf() 返回一个 Number 对象的基本数字值

JS String(字符串)对象

JavaScript String 对象用于处理字符串,其中提供了大量操作字符串的方法,以及一些属性。

创建 String 对象的语法格式如下:

var val = new String(value);
var val = String(value);

其中参数 value 为要创建的字符串或字符串对象。

JavaScript 中,字符串和字符串对象之间能够自由转换,因此不论是创建字符串对象还是直接声明字符串类型的变量,都可以直接使用字符串对象中提供的方法和属性。

1. String 对象中的属性

下表中列举了 String 对象中提供的属性及其描述信息:

属性 描述
constructor 获取创建此对象的 String() 函数的引用
length 获取字符串的长度
prototype 通过该属性您可以向对象中添加属性和方法

示例代码如下:

var str = new String('JavaScript');
String.prototype.name = null;
str.name = "Hello World!";
document.write(str.constructor + "<br>");       // 输出:function String() { [native code] }
document.write(str.length + "<br>");            // 输出:10
document.write(str.name);                       // 输出:Hello World!

2. String 对象中的方法

下表中列举了 String 对象中提供的方法及其描述信息:

方法 描述
anchor() 创建一个 HTML 锚点,即生成一个<a>标签,标签的 name 属性为 anchor() 方法中的参数
big() 用大号字体显示字符串
blink() 显示闪动的字符串
bold() 使用粗体显示字符串
charAt() 返回在指定位置的字符
charCodeAt() 返回指定字符的 Unicode 编码
concat() 拼接字符串
fixed() 以打字机文本显示字符串
fontcolor() 使用指定的颜色来显示字符串
fontsize() 使用指定的尺寸来显示字符串
fromCharCode() 将字符编码转换为一个字符串
indexOf() 检索字符串,获取给定字符串在字符串对象中首次出现的位置
italics() 使用斜体显示字符串
lastIndexOf() 获取给定字符串在字符串对象中最后出现的位置
link() 将字符串显示为链接
localeCompare() 返回一个数字,并使用该数字来表示字符串对象是大于、小于还是等于给定字符串
match() 根据正则表达式匹配字符串中的字符
replace() 替换与正则表达式匹配的子字符串
search() 获取与正则表达式相匹配字符串首次出现的位置
slice() 截取字符串的片断,并将其返回
small() 使用小字号来显示字符串
split() 根据给定字符将字符串分割为字符串数组
strike() 使用删除线来显示字符串
sub() 把字符串显示为下标
substr() 从指定索引位置截取指定长度的字符串
substring() 截取字符串中两个指定的索引之间的字符
sup() 把字符串显示为上标
toLocaleLowerCase() 把字符串转换为小写
toLocaleUpperCase() 把字符串转换为大写
toLowerCase() 把字符串转换为小写
toUpperCase() 把字符串转换为大写
toString() 返回字符串
valueOf() 返回某个字符串对象的原始值

示例代码如下:

var str = new String('JavaScript教程');

document.write(str.anchor("myanchor") + "<br>");     // 生成一段 HTML 代码:<a name="myanchor">JavaScript教程</a>
document.write(str.big() + "<br>");                  // 生成一段 HTML 代码:<big>JavaScript教程</big>
document.write(str.blink() + "<br>");                // 生成一段 HTML 代码:<blink>JavaScript教程</blink>
document.write(str.bold() + "<br>");                 // 生成一段 HTML 代码:<b>JavaScript教程</b>
document.write(str.charAt(10) + "<br>");             // 获取 str 中的第 11 个字符,输出:教
document.write(str.charCodeAt(10) + "<br>");         // 获取 str 中第 11 个字符的 Unicode 编码,输出:25945
document.write(str.concat(" String 对象") + "<br>"); // 将字符串“ String 对象”拼接到字符串 str 之后,输出:JavaScript教程 String 对象
document.write(str.fixed() + "<br>");                // 生成一段 HTML 代码:<tt>JavaScript教程</tt>
document.write(str.fontcolor("red") + "<br>");       // 生成一段 HTML 代码:<font color="red">JavaScript教程</font>
document.write(str.fontsize(2) + "<br>");            // 生成一段 HTML 代码:<font size="2">JavaScript教程</font>
document.write(String.fromCharCode(72,69,76,76,79) + "<br>");             // 将 Unicode 编码转换为具体的字符,输出:HELLO
document.write(str.indexOf("Script") + "<br>");             // 获取字符串“Script”在 str 中首次出现的为,输出:4
document.write(str.italics() + "<br>");                     // 生成一段 HTML 代码:<i>JavaScript教程</i>
document.write(str.lastIndexOf("a") + "<br>");              // 获取字符串“a”在 str 中最后一次出现的位置,输出 3
document.write(str.link("http://c.biancheng.net/") + "<br>");  // 生成一段 HTML 代码:<a href="http://c.biancheng.net/">JavaScript教程</a>
document.write(str.localeCompare("JavaScript") + "<br>");       // 比较字符串对象与给定字符串,返回:1
document.write(str.match(/[abc]/g) + "<br>");                   // 根据正则 /[abc]/g 检索 str,返回:a,a,c
document.write(str.replace(/[abc]/g, "Y") + "<br>");            // 使用字符串“Y”替换正则 /[abc]/g 匹配的字符,返回:JYvYSYript教程
document.write(str.search(/[Script]/g) + "<br>");               // 获取与正则匹配的字符串首次出现的位置,返回:4
document.write(str.slice(6,11) + "<br>");           // 截取字符串(获取 str 中第 7 到第 11 个字符),返回:ript教
document.write(str.small() + "<br>");               // 生成一段 HTML 代码:<small>JavaScript教程</small>
document.write(str.split("a") + "<br>");            // 根据“a”将字符串 str 拆分为数组,返回:J,v,Script教程
document.write(str.strike() + "<br>");              // 生成一段 HTML 代码:<strike>JavaScript教程</strike>
document.write(str.sub() + "<br>");                 // 生成一段 HTML 代码:<sub>JavaScript教程</sub>
document.write(str.substr(3, 7) + "<br>");          // 从第 4 个字符开始,向后截取 7 个字符,返回:aScript
document.write(str.substring(3, 7) + "<br>");       // 截取字符串(获取 str 中第 4 到第 7 个字符),返回:aScr
document.write(str.sup() + "<br>");                 // 生成一段 HTML 代码:<sup>JavaScript教程</sup>
document.write(str.toLocaleLowerCase() + "<br>");   // 返回:javascript教程
document.write(str.toLocaleUpperCase() + "<br>");   // 返回:JAVASCRIPT教程
document.write(str.toLowerCase() + "<br>");         // 返回:javascript教程
document.write(str.toUpperCase() + "<br>");         // 返回:JAVASCRIPT教程
document.write(str.toString() + "<br>");            // 返回:JavaScript教程
document.write(str.valueOf() + "<br>");             // 返回:JavaScript教程

3. 特殊字符

通过前面的学习我们知道,可以使用单引号和双引号来定义字符串,但如果字符串中也需要添加单引号或双引号该怎么办呢?我们可以使用反斜线 \ 来转义字符串中的引号,如下例所示:

var str1 = "He said \"Goodbye\"";
var str2 = 'it\'s okay';

除了单引号和双引号外,JavaScript 中还提供了一些能够使用反斜线转义的特殊字符,如下表所示:

代码 输出 代码 输出
\' 单引号 \r 回车
\" 双引号 \t tab
\\ 反斜线本身 \b 空格
\n 换行 \f 换页

JS Array(数组)对象

数组是值的有序集合,数组中的每个值称为一个元素,每个元素在数组中都有一个数字位置,称为索引,索引从 0 开始,依次递增。在 JavaScript 中,您可以使用 Array 对象定义数组,此外,Array 对象中还提供了各种有关数组的属性和方法。

创建 Array 对象的语法格式如下:

var arr = new Array(values);
var arr = Array(values);

其中,values 为数组中各个元素组成的列表,多个元素之间使用逗号分隔。

示例代码如下:

var fruits = new Array( "apple", "orange", "mango" );
console.log(fruits);  // 输出:["apple", "orange", "mango"]

提示:在使用 new Array() 来定义数组时,如果只提供一个数值参数,那么这个数值将用来表示数组的初始长度,例如 new Array(5) 表示定义一个长度为 5 的数组。JavaScript 中,数组允许的最大长度为 2³²-1,即 4294967295。

除了可以使用 Array() 函数来定义数组外,您也可以直接使用方括号 [ ] 来定义数组,[ ] 中为数组中的各个元素,多个元素之间使用逗号, 进行分隔。示例代码如下:

var fruits = [ "apple", "orange", "mango" ];
console.log(fruits);        // 输出:(3) ["apple", "orange", "mango"]

您可以通过数组的索引来访问数组中的各个元素,示例代码如下:

var fruits = [ "apple", "orange", "mango" ];
document.write(fruits[0] + "<br>");     // 输出:apple
document.write(fruits[1] + "<br>");     // 输出:orange
document.write(fruits[2] + "<br>");     // 输出:mango

1. Array 对象中的属性

下表中列举了 Array 对象中提供的属性及其描述信息:

属性 描述
constructor 返回创建数组对象的原型函数
length 设置或返回数组中元素的个数
prototype 通过该属性您可以向对象中添加属性和方法

示例代码如下:

var cars = new Array("Saab", "Volvo", "BMW");
Array.prototype.name = null;
cars.name = "JavaScript";
document.write(cars.constructor + "<br>");      // 输出:function Array() { [native code] }
document.write(cars.length + "<br>");           // 输出:3
document.write(cars.name + "<br>");             // 输出:JavaScript

2. Array 对象中的方法

下表中列举了 Array 对象中提供的方法及其描述信息:

方法 描述
concat() 拼接两个或更多的数组,并返回结果
copyWithin() 从数组的指定位置拷贝元素到数组的另一个指定位置中
entries() 返回数组的可迭代对象
every() 检测数值元素的每个元素是否都符合条件
fill() 使用一个固定值来填充数组
filter() 检测数值元素,并返回符合条件所有元素的数组
find() 返回符合传入函数条件的数组元素
findIndex() 返回符合传入函数条件的数组元素索引
forEach() 数组每个元素都执行一次回调函数
from() 通过给定的对象中创建一个数组
includes() 判断一个数组是否包含一个指定的值
indexOf() 搜索数组中的元素,并返回它所在的位置
isArray() 判断对象是否为数组
join() 把数组的所有元素放入一个字符串
keys() 返回数组的可迭代对象,包含原始数组的键(key)
lastIndexOf() 搜索数组中的元素,并返回它最后出现的位置
map() 通过指定函数处理数组的每个元素,并返回处理后的数组
pop() 删除数组的最后一个元素并返回删除的元素
push() 向数组的末尾添加一个或更多元素,并返回数组的长度
reduce() 累加(从左到右)数组中的所有元素,并返回结果
reduceRight() 累加(从右到左)数组中的所有元素,并返回结果
reverse() 反转数组中元素的顺序
shift() 删除并返回数组的第一个元素
slice() 截取数组的一部分,并返回这个新的数组
some() 检测数组元素中是否有元素符合指定条件
sort() 对数组的元素进行排序
splice() 从数组中添加或删除元素
toString() 把数组转换为字符串,并返回结果
unshift() 向数组的开头添加一个或多个元素,并返回新数组的长度
valueOf() 返回数组对象的原始值

示例代码如下:

var fruits = ["Orange", "Banana", "Apple", "Papaya", "Mango"];
document.write(fruits.entries() + "<br>");              // 返回:[object Array Iterator]
document.write(fruits.includes("Apple") + "<br>");      // 返回:true
document.write(fruits.fill("grape") + "<br>");          // 返回:grape,grape,grape,grape,grape
var fruits = ["Orange", "Banana", "Apple", "Papaya", "Mango"];
document.write(fruits.indexOf("Mango") + "<br>");               // 返回:4
document.write(Array.isArray(fruits) + "<br>");                 // 返回:true
document.write(fruits.join("-") + "<br>");                      // 返回:Orange-Banana-Apple-Papaya-Mango
document.write(fruits.lastIndexOf("Banana") + "<br>");          // 返回:1
document.write(fruits.pop() + "<br>");                          // 返回:Mango
document.write(fruits.push("Watermelon") + "<br>");             // 返回:5
document.write(fruits.unshift("Lemon","Pineapple") + "<br>");   // 返回:7
document.write(fruits.slice(1, 5) + "<br>");                    // 返回:Pineapple,Orange,Banana,Apple
document.write(fruits.sort() + "<br>");                         // 返回:Apple,Banana,Lemon,Orange,Papaya,Pineapple,Watermelon
document.write(fruits.valueOf() + "<br>");                      // 返回:Apple,Banana,Lemon,Orange,Papaya,Pineapple,Watermelon

JS Date(时间/日期)对象

Date 对象是 JavaScript 内置的对象,通过它您可以访问计算机系统的时间,此外,Date 对象中还提供了多种用于管理、操作和格式化时间/日期的方法。

1. 创建 Date 对象

在开始处理时间和日期之前,我们需要先创建一个 Date 对象。与其他对象(数组对象、字符串对象等)不同,Date 对象不能直接声明,必须通过 Date() 函数定义。

JavaScript 中提供了四种不同的方法来创建 Date 对象,如下所示:

var time = new Date();
var time = new Date(milliseconds);
var time = new Date(datestring);
var time = new Date(year, month, date[, hour, minute, second, millisecond]);

参数说明如下:

  • 不提供参数:若调用 Date() 函数时不提供参数,则创建一个包含当前时间和日期的 Date 对象;

  • milliseconds(毫秒):若提供一个数值作为参数,则会将这个参数视为一个以毫秒为单位的时间值,并返回自 1970-01-01 00:00:00 起,经过指定毫秒数的时间,例如 new Date(5000) 会返回一个 1970-01-01 00:00:00 经过 5000 毫秒之后的时间;

  • datestring(日期字符串):若提供一个字符串形式的日期作为参数,则会将其转换为具体的时间,日期的字符串形式有两种,如下所示:

    • YYYY/MM/dd HH:mm:ss(推荐):若省略时间部分,则返回的 Date 对象的时间为 00:00:00;
    • YYYY-MM-dd HH:mm:ss:若省略时间部分,则返回的 Date 对象的时间为 08:00:00(加上本地时区),若不省略,在 IE 浏览器中会转换失败。
  • 将具体的年月日、时分秒转换为 Date 对象,其中:

    • year:表示年,为了避免错误的产生,推荐使用四位的数字来表示年份;
    • month:表示月,0 代表 1 月,1 代表 2 月,以此类推;
    • date:表示月份中的某一天,1 代表 1 号,2 代表 2 号,以此类推;
    • hour:表示时,以 24 小时制表示,取值范围为 0 ~ 23;
    • minute:表示分,取值范围为 0 ~ 59;
    • second:表示秒,取值范围为 0 ~ 59;
    • millisecond:表示毫秒,取值范围为 0 ~ 999。

示例代码如下:

var time1 = new Date();
var time2 = new Date(1517356800000);
var time3 = new Date("2018/12/25 12:13:14");
var time4 = new Date(2020, 9, 12, 15, 16, 17);
document.write(time1 + "<br>");     // 输出:Fri Jul 23 2021 13:41:39 GMT+0800 (中国标准时间)
document.write(time2 + "<br>");     // 输出:Wed Jan 31 2018 08:00:00 GMT+0800 (中国标准时间)
document.write(time3 + "<br>");     // 输出:Tue Dec 25 2018 12:13:14 GMT+0800 (中国标准时间)
document.write(time4 + "<br>");     // 输出:Mon Oct 12 2020 15:16:17 GMT+0800 (中国标准时间)

2. Date 对象中的属性

下表中列举了 Date 属性中提供的属性及其描述:

属性 描述
constructor 返回创建 Date 对象的原型函数
prototype 通过该属性您可以向对象中添加属性和方法

示例代码如下:

var time = new Date();
Date.prototype.name = null;
time.name = "JavaScript";
document.write(time.constructor + "<br>");      // 输出:function Date() { [native code] }
document.write(time.name + "<br>");             // 输出:JavaScript

3. Date 对象中的方法

下表中列举了 Date 属性中提供的方法及其描述:

方法 描述
getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)
getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6)
getMonth() 从 Date 对象返回月份 (0 ~ 11)
getFullYear() 从 Date 对象返回四位数字的年份
getYear() 已废弃,请使用 getFullYear() 方法代替
getHours() 返回 Date 对象的小时 (0 ~ 23)
getMinutes() 返回 Date 对象的分钟 (0 ~ 59)
getSeconds() 返回 Date 对象的秒数 (0 ~ 59)
getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)
getTime() 返回 1970 年 1 月 1 日至今的毫秒数
getTimezoneOffset() 返回本地时间与格林威治标准时间 (GMT) 的分钟差
getUTCDate() 根据通用时间从 Date 对象返回月中的一天 (1 ~ 31)
getUTCDay() 根据通用时间从 Date 对象返回周中的一天 (0 ~ 6)
getUTCMonth() 根据通用时间从 Date 对象返回月份 (0 ~ 11)
getUTCFullYear() 根据通用时间从 Date 对象返回四位数的年份
getUTCHours() 根据通用时间返回 Date 对象的小时 (0 ~ 23)
getUTCMinutes() 根据通用时间返回 Date 对象的分钟 (0 ~ 59)
getUTCSeconds() 根据通用时间返回 Date 对象的秒钟 (0 ~ 59)
getUTCMilliseconds() 根据通用时间返回 Date 对象的毫秒(0 ~ 999)
parse() 返回1970年1月1日午夜到指定日期(字符串)的毫秒数
setDate() 设置 Date 对象中月的某一天 (1 ~ 31)
setMonth() 设置 Date 对象中月份 (0 ~ 11)
setFullYear() 设置 Date 对象中的年份(四位数字)
setYear() 已废弃,请使用 setFullYear() 方法代替
setHours() 设置 Date 对象中的小时 (0 ~ 23)
setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)
setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)
setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)
setTime() 以毫秒设置 Date 对象
setUTCDate() 根据通用时间设置 Date 对象中月份的一天 (1 ~ 31)
setUTCMonth() 根据通用时间设置 Date 对象中的月份 (0 ~ 11)
setUTCFullYear() 根据通用时间设置 Date 对象中的年份(四位数字)
setUTCHours() 根据通用时间设置 Date 对象中的小时 (0 ~ 23)
setUTCMinutes() 根据通用时间设置 Date 对象中的分钟 (0 ~ 59)
setUTCSeconds() 根据通用时间设置 Date 对象中的秒钟 (0 ~ 59)
setUTCMilliseconds() 根据通用时间设置 Date 对象中的毫秒 (0 ~ 999)
toSource() 返回该对象的源代码
toString() 把 Date 对象转换为字符串
toTimeString() 把 Date 对象的时间部分转换为字符串
toDateString() 把 Date 对象的日期部分转换为字符串
toGMTString() 已废弃,请使用 toUTCString() 方法代替
toUTCString() 根据通用时间,把 Date 对象转换为字符串
toLocaleString() 根据本地时间格式,把 Date 对象转换为字符串
toLocaleTimeString() 根据本地时间格式,把 Date 对象的时间部分转换为字符串
toLocaleDateString() 根据本地时间格式,把 Date 对象的日期部分转换为字符串
UTC() 根据通用时间返回 1970 年 1 月 1 日 到指定日期的毫秒数
valueOf() 返回 Date 对象的原始值

示例代码如下:

var time = new Date();
document.write(time.getDate() + "<br>");             // 输出:23
document.write(time.getDay() + "<br>");              // 输出:5
document.write(time.getFullYear() + "<br>");         // 输出:2021
document.write(time.getHours() + "<br>");            // 输出:16
document.write(time.getMonth() + "<br>");            // 输出:6
document.write(time.getTime() + "<br>");             // 输出:1627028869285
document.write(time.getUTCDate() + "<br>");          // 输出:23
document.write(time.toDateString() + "<br>");        // 输出:Fri Jul 23 2021
document.write(time.toString() + "<br>");            // 输出:Fri Jul 23 2021 16:29:57 GMT+0800 (中国标准时间)
document.write(time.toLocaleDateString() + "<br>");  // 输出:2021/7/23
document.write(time.toLocaleTimeString() + "<br>");  // 输出:下午4:31:00
document.write(time.toLocaleString() + "<br>");      // 输出:2021/7/23下午4:31:00

JS Math(数学)对象

Math 是 JavaScript 中的一个内置对象,其中提供了一些数学中常用的常量值和函数,用来实现一些数学中常见计算,例如计算平均数、求绝对值、四舍五入等。

与前面介绍的几个对象(例如 Number 对象、String 对象、Array 对象等)不同,调用 Math 对象中的属性和方法无需预先使用 new 运算符来创建它,直接将 Math 作为对象调用即可,例如:

var pi_val = Math.PI;                 // 数学中 π 的值:3.141592653589793
var abs_val = Math.sin(-5.35);  // -5.35 的绝对值:5.35

1. Math 对象中的属性

下表中列举了 Math 对象中提供的属性及其描述信息:

属性 描述
E 返回算术常量 e,即自然对数的底数(约等于 2.718)
LN2 返回 2 的自然对数(约等于 0.693)
LN10 返回 10 的自然对数(约等于 2.302)
LOG2E 返回以 2 为底的 e 的对数(约等于 1.443)
LOG10E 返回以 10 为底的 e 的对数(约等于 0.434)
PI 返回圆周率 π(约等于 3.14159)
SQRT1_2 返回返回 2 的平方根的倒数(约等于 0.707)
SQRT2 返回 2 的平方根(约等于 1.414)

示例代码如下:

document.write(Math.E + "<br>");            // 输出:2.718281828459045
document.write(Math.LN2 + "<br>");          // 输出:0.6931471805599453
document.write(Math.LN10 + "<br>");         // 输出:2.302585092994046
document.write(Math.LOG2E + "<br>");        // 输出:1.4426950408889634
document.write(Math.LOG10E + "<br>");       // 输出:0.4342944819032518
document.write(Math.PI + "<br>");           // 输出:3.141592653589793
document.write(Math.SQRT1_2 + "<br>");      // 输出:0.7071067811865476
document.write(Math.SQRT2 + "<br>");        // 输出:1.4142135623730951

2. Math 对象中的方法

下表中列举了 Math 对象中提供的方法及其描述信息:

方法 描述
abs(x) 返回 x 的绝对值
acos(x) 返回 x 的反余弦值
acosh(x) 返回 x 的反双曲余弦值
asin(x) 返回 x 的反正弦值
asinh(x) 返回 x 的反双曲正弦值
atan(x) 返回 x 的反正切值
atanh(x) 返回 x 的反双曲正切值
atan2(y,x) 返回 y/x 的反正切值
cbrt(x) 返回 x 的立方根
ceil(x) 对 x 进行向上取整,即返回大于 x 的最小整数
clz32(x) 返回将 x 转换成 32 无符号整形数字的二进制形式后,开头 0 的个数
cos(x) 返回 x 的余弦值
cosh(x) 返回 x 的双曲余弦值
exp(x) 返回算术常量 e 的 x 次方,即 Ex
expm1(x) 返回 exp(x) – 1 的值
floor(x) 对 x 进行向下取整,即返回小于 x 的最大整数
fround(x) 返回最接近 x 的单精度浮点数
hypot([x, [y, […]]]) 返回所有参数平方和的平方根
imul(x, y) 将参数 x、y 分别转换位 32 位整数,并返回它们相乘后的结果
log(x) 返回 x 的自然对数
log1p(x) 返回 x 加 1 后的自然对数
log10(x) 返回 x 以 10 为底的对数
log2(x) 返回 x 以 2 为底的对数
max([x, [y, […]]]) 返回多个参数中的最大值
min([x, [y, […]]]) 返回多个参数中的最小值
pow(x,y) 返回 x 的 y 次幂
random() 返回一个 0 到 1 之间的随机数
round(x) 返回 x 四舍五入后的整数
sign(x) 返回 x 的符号,即一个数是正数、负数还是 0
sin(x) 返回 x 的正弦值
sinh(x) 返回 x 的双曲正弦值
sqrt(x) 返回 x 的平方根
tan(x) 返回 x 的正切值
tanh(x) 返回 x 的双曲正切值
toSource() 返回字符串"Math"
trunc(x) 返回 x 的整数部分
valueOf() 返回 Math 对象的原始值

示例代码如下:

document.write(Math.abs(-3.1415) + "<br>");             // 输出:3.1415
document.write(Math.acos(0.5) + "<br>");                // 输出:1.0471975511965979
document.write(Math.ceil(1.45) + "<br>");               // 输出:2
document.write(Math.exp(1) + "<br>");                   // 输出:2.718281828459045
document.write(Math.floor(5.99) + "<br>");              // 输出:5
document.write(Math.log(6) + "<br>");                   // 输出:1.791759469228055
document.write(Math.max(4, 8, 1, 9) + "<br>");          // 输出:9
document.write(Math.min(4, 8, 1, 9) + "<br>");          // 输出:1
document.write(Math.random() + "<br>");                 // 输出:0.9172594288928195
document.write(Math.pow(2, 3) + "<br>");                // 输出:8
document.write(Math.sign(-123) + "<br>");               // 输出:-1
document.write(Math.sqrt(125) + "<br>");                // 输出:11.180339887498949

JS RegExp(正则表达式)对象

JavaScript 字符串是在编程中使用最多的一种数据类型,很多地方都需要对字符串进行操作,例如判断一个字符串是否为一个合法的 E-mail 地址、从字符串截取指定的部分等。

正则表达式是一种用于匹配字符串或特殊字符的一种逻辑公式,所谓逻辑公式就是由一些特定字符组合成的,用来表示某些规则的特殊字符串,可以表达对字符串数据的过滤逻辑。

在 JavaScript 中需要借助 RegExp 对象来使用正则表达式,要创建 RegExp 对象有两种方法,如下所示:

var patt = new RegExp(pattern, modifiers);
var patt = /pattern/modifiers;

参数说明如下:

  • pattern:正则表达式,按照正则表达式的语法定义的正则表达式;
  • modifiers:修饰符,用来设置字符串的匹配模式,可选值如下表所示:
修饰符 描述
i 执行对大小写不敏感的匹配
g 执行全局匹配(查找所有的匹配项,而非在找到第一个匹配项后停止)
m 执行多行匹配
s 允许使用 . 匹配换行符
u 使用 Unicode 码的模式进行匹配
y 执行“粘性”搜索,匹配从目标字符串的当前位置开始

注意:当使用 new 关键字创建 RegExp 对象时,需要将正则表达式中的特殊字符转义,即在特殊字符前加反斜杠 \,例如 \w+。

1. 定义正则表达式

正则表达式由字母、数字、标点以及一些特殊特殊字符组成,例如 /abc/、/(\d+).\d*/,可以在正则表达式中使用的特殊字符如下表所示:

特殊字符 含义
\ 转义字符,在非特殊字符之前使用反斜杠表示下一个字符是特殊字符,不能按照字面理解,例如 \b 表示一个字符边界;在特殊字符之前使用反斜杠则表示下一个字符不是特殊字符,应该按照字面理解。例如反斜杠本身,若要在正则表达式中定义一个反斜杠,则需要在反斜杠前再添加一个反斜杠 \。
^ 匹配字符串的开头,如果设置了修饰符 m,则也可以匹配换行符后紧跟的位置。 例如“/^A/”并不会匹配“an A”中的“A”,但是会匹配“An E”中的“A”。
$ 匹配字符串的末尾,如果设置了修饰符 m,则也可以匹配换行符之前的位置。 例如“/t$/”并不会匹配“eater”中的“t”,但是会匹配“eat”中的“t”。
* 匹配前一个表达式 0 次或多次,等价于 {0,}。例如“/bo*/”能够匹配“A ghost boooooed”中的“booooo”和“A bird warbled”中的“b”,但是在“A goat grunted”中不会匹配任何内容。
+ 匹配前面一个表达式 1 次或者多次,等价于 {1,}。例如“/a+/”能够匹配“candy”中的“a”和“caaaaaaandy”中所有的“a”,但是在“cndy”中不会匹配任何内容。
? 匹配前面一个表达式 0 次或者 1 次,等价于 {0,1}。例如“/e?le?/”能够匹配“angel”中的“el”,“angle”中的“le”以及“oslo”中的“l”。
. 匹配除换行符之外的任何单个字符。例如“/.n/”将会匹配“nay, an apple is on the tree”中的“an”和“on”。
(x) 匹配“x”并记住这一匹配项,这里的括号被称为捕获括号。
(?:x) 匹配“x”但是不记住匹配项,这里的括号被称为非捕获括号。
x(?=y) 当“x”后面跟着“y”时,匹配其中的“x”。例如“/Jack(?=Sprat)/”会匹配后面跟着“Sprat”的“Jack”,“/Jack(?=Sprat
(?<=y)x 当“x”前面是“y”时,匹配其中的“x”。例如“/(?<=Jack)Sprat/”会匹配前面未“Sprat”的“Jack”,“/(?<=Jack
x(?!y) 当“x”后面不是“y”时,匹配其中的“x”。 例如“/\d+(?!.)/”会匹配“3.141”中的“141”,而不是“3.141”。
(?<!y)x 当“x”前面不是“y”时,匹配其中的“x”。
xly 匹配“x”或者“y”。 例如“/greenlred/”能够匹配“green apple”中的“green”和“red apple”中的“red”。
{n} n 是一个正整数,表示匹配前一个字符 n 次。例如“/a{2}/”不会匹配“candy”中的“a”,但是能够匹配“caandy”中所有的“a”,以及“caaandy”中的前两个“a”。
{n,} n 是一个正整数,表示匹配前一个字符至少 n 次。例如“/a{2,}/”能够匹配“aa”、“aaaa”或“aaaaa”,但不会匹配“a”。
{n,m} n 和 m 都是整数,表示匹配前一个字符至少 n 次,最多 m 次,如果 n 或 m 等于 0,则表示忽略这个值。例如“/a{1, 3}/”能够匹配“candy”中的“a”,“caandy”中的前两个“a”,“caaaaaaandy”中的前三个“a”。
[xyz] 转义序列,匹配 x、y 或 z,您也可以使用破折号-来指定一个字符范围。例如“[abcd]”和“[a-d]”是一样的,它们都能匹配“brisket”中的“b”,“city”中的“c”。
[^xyz] 反向字符集,匹配除 x、y、z 以外的任何字符,您通用也可以使用破折号 – 来指定一个字符范围。例如“[abc]”和“[a-c]”是一样的,它们都能匹配“brisket”中的“r”,“chop”中的“h”。
[\b] 匹配一个退格符,注意:不要和 \b 混淆。
\b 匹配一个单词的边界,即单词的开始或末尾。例如“/\bm/”能够匹配“moon”中的“m”,但不会匹配“imoon”中的“m”。
\B 匹配一个非单词边界。例如“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
\cX 当 X 是 A 到 Z 之间的字符时,匹配字符串中的一个控制符。例如“/\cM/”能够匹配字符串中的“control-M(U+000D)”。
\d 匹配一个数字,等价于“[0-9]”。例如“/\d/”或者“/[0-9]/”能够匹配“B2 is the suite number.”中的“2”。
\D 匹配一个非数字字符,等价于“[^0-9]”。 例如“/\D/”或者“/[^0-9]/”能够匹配“B2 is the suite number.”中的“B”。
\f 匹配一个换页符 (U+000C)。
\n 匹配一个换行符 (U+000A)。
\r 匹配一个回车符 (U+000D)。
\s 匹配一个空白字符,包括空格、制表符、换页符和换行符,等价于“[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]”。例如“/\s\w*/”能够匹配“foo bar.”中的“bar”。
\S 匹配一个非空白字符,等价于“[^\f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]”。例如“/\S\w*/”能够匹配“foo bar.”中的“foo”。
\t 匹配一个水平制表符 (U+0009)。
\v 匹配一个垂直制表符 (U+000B)。
\w 匹配一个单字字符(字母、数字或者下划线),等价于“[A-Za-z0-9_]”。例如“/\w/”能够匹配“apple,”中的“a”,“$5.28,”中的“5”和“3D.”中的“3”。
\W 匹配一个非单字字符,等价于“[A-Za-z0-9_]”。例如“/\W/”或者“/[A-Za-z0-9_]/”能够匹配“50%.”中的“%”。
\n 获取最后的第 n 个匹配的值。比如“/apple(,)\sorange\1/”能够匹配“apple, orange, cherry, peach.”中的“apple, orange,”。
\0 匹配 NULL(U+0000)字符,不要在这后面跟其它小数,因为 \0 是一个八进制转义序列。
\xhh 匹配一个两位十六进制数(\x00-\xFF)表示的字符。
\uhhhh 匹配一个四位十六进制数表示的 UTF-16 代码单元。
\u{hhhh}或\u{hhhhh} (仅在设置了修饰符 u 时)匹配一个十六进制数表示的 Unicode 字符。

提示:在正则表达式中 .*?+[](){}^$|\ 等字符被赋予了特殊的含义,若要在正则表达式中使用这些字符的原本意思时,需要在这些字符前添加反斜线进行转义,例如若要匹配 .,则必须编写为 \.。

2. 使用正则表达式

JavaScript RegExp 对象中提供了一些列方法来执行正则表达式,如下表所示:

方法 描述
compile() 在 1.5 版本中已废弃,编译正则表达式
exec() 在字符串搜索匹配项,并返回一个数组,若没有匹配项则返回 null
test() 测试字符串是否与正则表达式匹配,匹配则返回 true,不匹配则返回 false
toString() 返回表示指定对象的字符串

此外 String 对象中也提供了一些方法来执行正则表达式,如下表所示:

方法 描述
search() 在字符串中搜索匹配项,并返回第一个匹配的结果,若没有找到匹配项则返回 -1
match() 在字符串搜索匹配项,并返回一个数组,若没有匹配项则返回 null
matchAll() 在字符串搜索所有匹配项,并返回一个迭代器(iterator)
replace() 替换字符串中与正则表达式相匹配的部分
split() 按照正则表达式将字符串拆分为一个字符串数组

除了方法外,RegExp 对象中还提供了一些属性,如下所示:

属性 描述
constructor 返回一个函数,该函数是一个创建 RegExp 对象的原型
global 判断是否设置了修饰符 “g”
ignoreCase 判断是否设置了修饰符 “i”
lastIndex 用于规定下次匹配的起始位置
multiline 判断是否设置了修饰符 “m”
source 返回正则表达式的匹配模式

示例代码如下:

var str = "Hello World!";
var reg = /[a-g]/g;
document.write(reg.exec(str) + "<br>");             // 输出:e
document.write(reg.test(str) + "<br>");             // 输出:true
document.write(reg.toString() + "<br>");            // 输出:/[a-g]/g
document.write(str.search(reg) + "<br>");           // 输出:1
document.write(str.match(reg) + "<br>");            // 输出:e,d
document.write(str.matchAll(reg) + "<br>");         // 输出:[object RegExp String Iterator]
document.write(str.replace(reg, "+") + "<br>");     // 输出:H+llo Worl+!
document.write(str.split(reg) + "<br>");            // 输出:H,llo Worl,!

JS DOM(文档对象模型)

文档对象模型(Document Object Model,简称 DOM),是一种与平台和语言无关的模型,用来表示 HTML 或 XML 文档。文档对象模型中定义了文档的逻辑结构,以及程序访问和操作文档的方式。

当网页加载时,浏览器就会自动创建当前页面的文档对象模型(DOM)。在 DOM 中,文档的所有部分(例如元素、属性、文本等)都会被组织成一个逻辑树结构(类似于族谱),树中每一个分支的终点称为一个节点,每个节点都是一个对象,如下图所示:
在这里插入图片描述
借助 DOM 您可以使用 JavaScript 来访问、修改、删除或添加 HTML 文档中的任何内容。

1. Document 对象

当浏览器加载一个 HTML 文档时,会创建一个 Document 对象,Document 对象是 DOM 树中所有节点的根节点。通过 Document 对象我们可以访问 HTML 文档中的所有元素。

提示:Document 对象是 Window 对象的一部分,所以您可以通过 window.document 来访问 Document 对象。

2. Document 对象中的属性

下表中列举了 Document 对象中提供的属性及其描述:

属性 描述
document.activeElement 返回当前获取焦点的元素
document.anchors 返回对文档中所有 Anchor 对象的引用
document.applets 返回对文档中所有 Applet 对象的引用。注意: HTML5 已不支持 元素
document.baseURI 返回文档的基础 URI
document.body 返回文档的 body 元素
document.cookie 设置或返回与当前文档有关的所有 cookie
document.doctype 返回与文档相关的文档类型声明 (DTD)
document.documentElement 返回文档的根节点
document.documentMode 返回浏览器渲染文档的模式
document.documentURI 设置或返回文档的位置
document.domain 返回当前文档的域名
document.domConfig 已废弃,返回 normalizeDocument() 被调用时所使用的配置
document.embeds 返回文档中所有嵌入内容(embed)的集合
document.forms 返回文档中所有 Form 对象的引用
document.images 返回文档中所有 Image 对象的引用
document.implementation 返回处理该文档的 DOMImplementation 对象
document.inputEncoding 返回文档的编码方式
document.lastModified 返回文档的最后修改日期
document.links 返回对文档中所有 Area 和 Link 对象的引用
document.readyState 返回文档状态(载入中)
document.referrer 返回载入当前文档的 URL
document.scripts 返回页面中所有脚本的集合
document.strictErrorChecking 设置或返回是否强制进行错误检查
document.title 返回当前文档的标题
document.URL 返回文档的完整 URL

3. Document 对象中的方法

下表中列举了 Document 对象中提供的方法及其描述:

方法 描述
document.addEventListener() 向文档中添加事件
document.adoptNode(node) 从另外一个文档返回 adapded 节点到当前文档
document.close() 关闭使用 document.open() 方法打开的输出流,并显示选定的数据
document.createAttribute() 为指定标签添加一个属性节点
document.createComment() 创建一个注释节点
document.createDocumentFragment() 创建空的 DocumentFragment 对象,并返回此对象
document.createElement() 创建一个元素节点
document.createTextNode() 创建一个文本节点
document.getElementsByClassName() 返回文档中所有具有指定类名的元素集合
document.getElementById() 返回文档中具有指定 id 属性的元素
document.getElementsByName() 返回具有指定 name 属性的对象集合
document.getElementsByTagName() 返回具有指定标签名的对象集合
document.importNode() 把一个节点从另一个文档复制到该文档以便应用
document.normalize() 删除空文本节点,并合并相邻的文本节点
document.normalizeDocument() 删除空文本节点,并合并相邻的节点
document.open() 打开一个流,以收集来自 document.write() 或 document.writeln()
document.querySelector() 返回文档中具有指定 CSS 选择器的第一个元素
document.querySelectorAll() 返回文档中具有指定 CSS 选择器的所有元素
document.removeEventListener() 移除文档中的事件句柄
document.renameNode() 重命名元素或者属性节点
document.write() 向文档中写入某些内容
document.writeln() 等同于 write() 方法,不同的是 writeln() 方法会在末尾输出一个换行符

示例代码如下:

document.addEventListener("click", function(){
    document.body.innerHTML = document.activeElement;
    var box = document.createElement('div');
    document.body.appendChild(box);
    var att = document.createAttribute('id');
    att.value = "myDiv";
    document.getElementsByTagName('div')[0].setAttributeNode(att);
    document.getElementById("myDiv").innerHTML = Math.random();
    var btn = document.createElement("button");
    var t = document.createTextNode("按钮");
    btn.appendChild(t);
    document.body.appendChild(btn);
    var att = document.createAttribute('onclick');
    att.value = "myfunction()";
    document.getElementsByTagName('button')[0].setAttributeNode(att);
});
function myfunction(){
    alert(document.title);
}

运行上面的代码,点击页面的空白区域,即可输出如下图所示的内容:
在这里插入图片描述

JS Element对象(元素对象)

通过《文档对象模型》一节的学习我们知道,当网页加载时,浏览器就会自动创建当前页面的文档对象模型(DOM),并将文档的所有部分(例如元素、属性、文本等)组织成一个逻辑树结构(类似于族谱),逻辑树的每一个分支的终点称为一个节点,每个节点都包含一个对象,这个对象就是我们本节要介绍的 Element 对象。

使用 Document 对象中提供的方法(例如 getElementsByTagName()、getElementById()、getElementsByClassName() 等)可以得到 Element 对象,在 Element 对象中同样也提供了一系列方法和属性,来操作文档中的元素或者元素中的属性。

1. Element 对象中的属性

下表中列举了 JavaScript Element 对象中提供的属性及其描述:

属性 描述
element.accessKey 设置或返回一个访问单选按钮的快捷键
element.attributes 返回一个元素的属性数组
element.childNodes 返回元素的一个子节点的数组
element.children 返回元素中子元素的集合
element.classList 返回元素中类名组成的对象
element.className 设置或返回元素的 class 属性
element.clientHeight 返回内容的可视高度(不包括边框,边距或滚动条)
element.clientWidth 返回内容的可视宽度(不包括边框,边距或滚动条)
element.contentEditable 设置或返回元素的内容是否可编辑
element.dir 设置或返回一个元素中的文本方向
element.firstChild 返回元素中的第一个子元素
element.id 设置或者返回元素的 id
element.innerHTML 设置或者返回元素的内容
element.isContentEditable 返回元素内容是否可编辑,如果可编辑则返回 true,否则返回 false
element.lang 设置或者返回一个元素的语言
element.lastChild 返回元素的最后一个子元素
element.namespaceURI 返回命名空间的 URI
element.nextSibling 返回指定元素之后的兄弟元素,两个元素在 DOM 树中位于同一层级(包括文本节点、注释节点)
element.nextElementSibling 返回指定元素之后的兄弟元素,两个元素在 DOM 树中位于同一层级(不包括文本节点、注释节点)
element.nodeName 返回元素名称(大写)
element.nodeType 返回元素的节点类型
element.nodeValue 返回元素的节点值
element.offsetHeight 返回元素的高度,包括边框和内边距,但不包括外边距
element.offsetWidth 返回元素的宽度,包括边框和内边距,但不包括外边距
element.offsetLeft 返回元素在水平方向的偏移量
element.offsetParent 返回距离该元素最近的进行过定位的父元素
element.offsetTop 返回元素在垂直方向的偏移量
element.ownerDocument 返回元素的根元素(文档对象)
element.parentNode 返回元素的父节点
element.previousSibling 返回元素之前的兄弟元素,两个元素在 DOM 树中位于同一层级(包括文本节点、注释节点)
element.previousElementSibling 返回元素之前的兄弟元素,两个元素在 DOM 树中位于同一层级(不包括文本节点、注释节点)
element.scrollHeight 返回元素的完整高度(包括被滚动条隐蔽的部分)
element.scrollLeft 设置或返回元素滚动条距离元素左侧的距离
element.scrollTop 设置或返回元素滚动条距离元素上方的距离
element.scrollWidth 返回元素的完整宽度(包括被滚动条隐蔽的部分)
element.style 设置或返回元素的样式属性
element.tabIndex 设置或返回元素的标签顺序
element.tagName 以字符的形式返回元素的名称(大写)
element.textContent 设置或返回某个元素以及其中的文本内容
element.title 设置或返回元素的 title 属性
element.length 返回对象的长度

2. Element 对象中的方法

下表中列举了 JavaScript Element 对象中提供的方法及其描述:

方法 描述
element.addEventListener() 为指定元素定义事件
element.appendChild() 为元素添加一个新的子元素
element.cloneNode() 克隆某个元素
element.compareDocumentPosition() 比较当前元素与指定元素在文档中的位置,返回值如下:1:表示两个元素没有关系,不属于同一文档;2:表示当前元素在指定元素之后;4:当前元素在指定元素之前;8:当前元素在指定元素之内;16:指定元素在当前元素之内;32:两个元素没有关系,或者它们是同一元素的两个属性。
element.focus() 使元素获得焦点
element.getAttribute() 通过属性名称获取指定元素的属性值
element.getAttributeNode() 通过属性名称获取指定元素得属性节点
element.getElementsByTagName() 通过标签名获取当前元素下的所有子元素的集合
element.getElementsByClassName() 通过类名获取当前元素下的子元素的集合
element.hasAttribute() 判断元素是否具有指定的属性,若存在则返回 true,不存在则返回 false
element.hasAttributes() 判断元素是否存在任何属性,若存在则返回 true,不存在则返回 false
element.hasChildNodes() 判断一个元素是否具有子元素,有则返回 true,没有则返回 false
element.hasFocus() 判断元素是否获得了焦点
element.insertBefore() 在已有子元素之前插入一个新的子元素
element.isDefaultNamespace() 如果指定 namespaceURI 是默认的则返回 true,否则返回 false。
element.isEqualNode() 检查两个元素是否相等
element.isSameNode() 检查当前元素与指定元素是否为同一元素
element.isSupported() 判断当前元素是否支持某个特性
element.normalize() 合并相邻的文本节点,并删除空的文本节点
element.querySelector() 根据 CSS 选择器,返回第一个匹配的元素
document.querySelectorAll() 根据 CSS 选择器,返回所有匹配的元素
element.removeAttribute() 从元素中删除指定的属性
element.removeAttributeNode() 从元素中删除指定的属性节点
element.removeChild() 删除一个子元素
element.removeEventListener() 移除由 addEventListener() 方法添加的事件
element.replaceChild() 替换一个子元素
element.setAttribute() 设置或者修改指定属性的值
element.setAttributeNode() 设置或者修改指定的属性节点
element.setUserData() 在元素中为指定键值关联对象
element.toString() 将元素转换成字符串
nodelist.item() 返回某个元素基于文档树的索引

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body onload="accesskey()">
    <a id="r" class="aaa bbb ccc" href="javascript:;">使用 Alt + r 访问该元素</a><br>
    <a id="g" href="javascript:;">使用 Alt + g 访问该元素</a>
    <script type="text/javascript">
        function accesskey(){
            document.getElementById('r').accessKey="r"
            document.getElementById('g').accessKey="g"
        }
        var ele = document.getElementById('r');
        console.log(ele.attributes);                            // 输出:NamedNodeMap {0: id, 1: href, id: id, href: href, length: 2}
        console.log(document.body.childNodes);                  // 输出:NodeList(7) [text, a#r, br, text, a#g, text, script]
        console.log(ele.classList);                             // 输出:DOMTokenList(3) ["aaa", "bbb", "ccc", value: "aaa bbb ccc"]
        console.log(ele.className);                             // 输出:aaa bbb ccc
        console.log(ele.clientHeight);                          // 输出:DOMTokenList(3) ["aaa", "bbb", "ccc", value: "aaa bbb ccc"]
        console.log(ele.tagName);                               // 输出:A
        console.log(ele.compareDocumentPosition(document.getElementById('g')));     // 输出:4
        console.log(ele.getAttribute('href'));                  // 输出:javascript:;
        console.log(ele.getAttributeNode('href'));              // 输出:href="javascript:;"
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

JS attributes对象(元素属性对象)

元素属性是指在 HTML 元素的开始标签中用来控制标签行为或提供标签信息的特殊词语。

在 HTML DOM 中,通过 attributes 对象来表示 HTML 属性,在 attributes 对象中提供了多种添加、修改和删除 HTML 属性的方法,如下表所示:

属性 / 方法 描述
attributes.isId 如果属性是 ID 类型,则返回 true,否则返回 false
attributes.name 返回属性名称
attributes.value 设置或者返回属性的值
attributes.specified 如果定义了指定属性,则返回 true,否则返回 false
nodemap.getNamedItem() 从节点列表中返回的指定属性节点
nodemap.item() 返回节点列表中处于指定索引号的节点
nodemap.length 返回节点列表的节点数目
nodemap.removeNamedItem() 删除指定属性节点
nodemap.setNamedItem() 设置指定属性节点(通过名称)

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <a href="javascript:;" target="_blank" id="myLink">JavaScript</a><br>
    <script type="text/javascript">
        var atag = document.getElementById('myLink');
        var attr = atag.attributes;
        document.write(attr.target.value + "<br>");                 // 输出:_blank
        document.write(attr.target.name + "<br>");                  // 输出:target
        document.write(attr.target.specified + "<br>");             // 输出:true
        document.write(attr.getNamedItem('href').textContent + "<br>");  // 输出:javascript:;
        document.write(attr.item(0).name + "<br>");                 // 输出:href
        document.write(attr.length + "<br>");                       // 输出:3
        document.write(attr.removeNamedItem('target') + "<br>");    // 输出:[object Attr]
        var cla = document.createAttribute('class');
        cla.value = 'democlass';
        document.write(attr.setNamedItem(cla) + "<br>");            // 输出:null
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

JS BOM(浏览器对象模型)

浏览器对象模型(Browser Object Model,简称 BOM)是 JavaScript 的组成部分之一,BOM 赋予了 JavaScript 程序与浏览器交互的能力。

window 对象是 BOM 的核心,用来表示当前浏览器窗口,其中提供了一系列用来操作或访问浏览器的方法和属性。另外,JavaScript 中的所有全局对象、函数以及变量也都属于 window 对象,甚至我们前面介绍的 document 对象也属于 window 对象。

注意:如果 HTML 文档中包含框架( 或 标签),浏览器会为 HTML 文档创建一个 window 对象的同时,为每个框架创建一个额外的 window 对象。

1. window 对象中的属性

下表中列举了 window 对象中提供的属性及其描述:

属性 描述
closed 返回窗口是否已被关闭
defaultStatus 设置或返回窗口状态栏中的默认文本
document 对 Document 对象的只读引用
frames 返回窗口中所有已经命名的框架集合,集合由 Window 对象组成,每个 Window 对象在窗口中含有一个 或 标签
history 对 History 对象的只读引用,该对象中包含了用户在浏览器中访问过的 URL
innerHeight 返回浏览器窗口的高度,不包含工具栏与滚动条
innerWidth 返回浏览器窗口的宽度,不包含工具栏与滚动条
localStorage 在浏览器中以键值对的形式保存某些数据,保存的数据没有过期时间,会永久保存在浏览器中,直至手动删除
length 返回当前窗口中 框架的数量
location 引用窗口或框架的 Location 对象,该对象中包含当前 URL 的有关信息
name 设置或返回窗口的名称
navigator 对 Navigator 对象的只读引用,该对象中包含当前浏览器的有关信息
opener 返回对创建此窗口的 window 对象的引用
outerHeight 返回浏览器窗口的完整高度,包含工具栏与滚动条
outerWidth 返回浏览器窗口的完整宽度,包含工具栏与滚动条
pageXOffset 设置或返回当前页面相对于浏览器窗口左上角沿水平方向滚动的距离
pageYOffset 设置或返回当前页面相对于浏览器窗口左上角沿垂直方向滚动的距离
parent 返回父窗口
screen 对 Screen 对象的只读引用,该对象中包含计算机屏幕的相关信息
screenLeft 返回浏览器窗口相对于计算机屏幕的 X 坐标
screenTop 返回浏览器窗口相对于计算机屏幕的 Y 坐标
screenX 返回浏览器窗口相对于计算机屏幕的 X 坐标
sessionStorage 在浏览器中以键值对的形式存储一些数据,数据会在关闭浏览器窗口或标签页之后删除
screenY 返回浏览器窗口相对于计算机屏幕的 Y 坐标
self 返回对 window 对象的引用
status 设置窗口状态栏的文本
top 返回最顶层的父窗口

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        window.defaultStatus = "JavaScript"
        document.write(window.defaultStatus + "<br>");    // 输出:JavaScript
        document.write(window.innerHeight + "<br>");      // 输出:314
        document.write(window.innerWidth + "<br>");       // 输出:539
        document.write(window.length + "<br>");           // 输出:0
        document.write(window.location + "<br>");         // 输出:file:///F:/code/index.html
        document.write(window.opener + "<br>");           // 输出:null
        document.write(window.outerHeight + "<br>");      // 输出:558
        document.write(window.outerWidth + "<br>");       // 输出:555
        document.write(window.parent + "<br>");           // 输出:[object Window]
        document.write(window.screenLeft + "<br>");       // 输出:2263
        document.write(window.screenTop + "<br>");        // 输出:401
        document.write(window.screenX + "<br>");          // 输出:2263
        document.write(window.screenY + "<br>");          // 输出:401
    </script>
</body>
</html>

2. window 对象中的方法

下表中列举了 window 对象中提供的方法及其描述:

方法 描述
alert() 在浏览器窗口中弹出一个提示框,提示框中有一个确认按钮
atob() 解码一个 base-64 编码的字符串
btoa() 创建一个 base-64 编码的字符串
blur() 把键盘焦点从顶层窗口移开
clearInterval() 取消由 setInterval() 方法设置的定时器
clearTimeout() 取消由 setTimeout() 方法设置的定时器
close() 关闭某个浏览器窗口
confirm() 在浏览器中弹出一个对话框,对话框带有一个确认按钮和一个取消按钮
createPopup() 创建一个弹出窗口,注意:只有 IE 浏览器支持该方法
focus() 使一个窗口获得焦点
getSelection() 返回一个 Selection 对象,对象中包含用户选中的文本或光标当前的位置
getComputedStyle() 获取指定元素的 CSS 样式
matchMedia() 返回一个 MediaQueryList 对象,表示指定的媒体查询解析后的结果
moveBy() 将浏览器窗口移动指定的像素
moveTo() 将浏览器窗口移动到一个指定的坐标
open() 打开一个新的浏览器窗口或查找一个已命名的窗口
print() 打印当前窗口的内容
prompt() 显示一个可供用户输入的对话框
resizeBy() 按照指定的像素调整窗口的大小,即将窗口的尺寸增加或减少指定的像素
resizeTo() 将窗口的大小调整到指定的宽度和高度
scroll() 已废弃。您可以使用 scrollTo() 方法来替代
scrollBy() 将窗口的内容滚动指定的像素
scrollTo() 将窗口的内容滚动到指定的坐标
setInterval() 创建一个定时器,按照指定的时长(以毫秒计)来不断调用指定的函数或表达式
setTimeout() 创建一个定时器,在经过指定的时长(以毫秒计)后调用指定函数或表达式,只执行一次
stop() 停止页面载入
postMessage() 安全地实现跨源通信

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <p id="show_tag">此处显示点击按钮的效果</p>
    <button onclick="myBtoa()">btoa()</button>
    <button onclick="myAtob()">atob()</button>
    <button onclick="myAlert()">alert()</button>
    <button onclick="myConfirm()">confirm()</button>
    <button onclick="myOpen()">open()</button>
    <button onclick="myMoveBy()">moveBy()</button>
    <button onclick="myMoveTo()">moveTo()</button>
    <button onclick="myPrint()">print()</button>
    <button onclick="myPrompt()">prompt()</button>
    <button onclick="myResizeBy()">resizeBy()</button>
    <button onclick="myClose()">close()</button>
    <script type="text/javascript">
        var ptag = document.getElementById('show_tag');
        var str;
        function myBtoa(){
            str = btoa("JavaScript");
            ptag.innerHTML = str;
        }
        function myAtob(){
            ptag.innerHTML = typeof str;
            if(str == undefined){
                ptag.innerHTML = "请先点击 btoa() 按钮";
                return;
            }
            ptag.innerHTML = atob(str);
        }
        function myAlert(){
            alert("这是一个提示框!");
        }
        function myConfirm(){
            var x;
            var r = confirm("按下按钮!");
            if (r == true){
                x = "你按下了\"确定\"按钮!";
            }
            else{
                x = "你按下了\"取消\"按钮!";
            }
            ptag.innerHTML = x;
        }
        var myWin;
        function myOpen(){
            if(myWin == undefined || (myWin != undefined && myWin.closed == true)){
                myWin = window.open('', '', 'width=200,height=100');
            }else{
                return;
            }
        }
        function myMoveBy(){
            if(myWin == undefined || myWin.closed == true) myOpen();
            myWin.moveBy(200, 200);
        }
        function myMoveTo(){
            if(myWin == undefined || myWin.closed == true) myOpen();
            myWin.moveTo(0, 0);
        }
        function myPrint(){
            print();
        }
        function myPrompt(){
            var name = prompt("请输入你的名字。")
            if (name != null && name != ""){
                ptag.innerHTML = "你好 " + name  + "! 今天感觉如何?";
            } else {
                ptag.innerHTML = "你没有输入任何内容";
            }
        }
        function myResizeBy(){
            if(myWin == undefined || myWin.closed == true) myOpen();
            myWin.resizeBy(100, 100);
        }
        function myClose(){
            if(myWin == undefined) return;
            if(myWin != undefined && myWin.closed == false) myWin.close();
        }
    </script>
</body>
</html>

运行结果如下图所示,点击页面中的按钮即可实现相应功能。
在这里插入图片描述

JS Navigator对象:获取浏览器信息

JavaScript navigator 对象中存储了与浏览器相关的信息,例如名称、版本等,我们可以通过 window 对象的 navigator 属性(即 window.navigator)来引用 navigator 对象,并通过它来获取浏览器的基本信息。

由于 window 对象是一个全局对象,因此在使用 window.navigator 时可以省略 window 前缀,例如 window.navigator.appName 可以简写为 navigator.appName

1. navigator 对象中的属性

下表中列举了 JavaScript navigator 对象中常用的属性及其描述:

属性 描述
appCodeName 返回当前浏览器的内部名称(开发代号)
appName 返回浏览器的官方名称
appVersion 返回浏览器的平台和版本信息
cookieEnabled 返回浏览器是否启用 cookie,启用返回 true,禁用返回 false
onLine 返回浏览器是否联网,联网则返回 true,断网则返回 false
platform 返回浏览器运行的操作系统平台
userAgent 返回浏览器的厂商和版本信息,即浏览器运行的操作系统、浏览器的版本、名称

2. navigator 对象中的方法

下表中列举了JavaScript navigator 对象中提供的方法及其描述:

方法 描述
javaEnabled() 返回浏览器是否支持运行 Java Applet 小程序,支持则返回 true,不支持则返回 false
sendBeacon() 向浏览器异步传输少量数据

示例代码如下所示:

document.write("navigator.appCodeName:" + navigator.appCodeName + "<br>");
document.write("navigator.appName:" + navigator.appName + "<br>");
document.write("navigator.appVersion:" + navigator.appVersion + "<br>");
document.write("navigator.cookieEnabled:" + navigator.cookieEnabled + "<br>");
document.write("navigator.onLine:" + navigator.onLine + "<br>");
document.write("navigator.platform:" + navigator.platform + "<br>");
document.write("navigator.userAgent:" + navigator.userAgent + "<br>");
document.write("navigator.javaEnabled():" + navigator.javaEnabled() + "<br>");

运行结果如下所示:

navigator.appCodeName:Mozilla navigator.appName:Netscape
navigator.appVersion:5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124
Safari/537.36 navigator.cookieEnabled:true navigator.onLine:true
navigator.platform:Win32 navigator.userAgent:Mozilla/5.0 (Windows NT
10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 navigator.javaEnabled():false

JS Screen对象:获取屏幕信息

JavaScript screen 对象中包含了有关计算机屏幕的信息,例如分辨率、宽度、高度等,我们可以通过 window 对象的 screen 属性来获取它。由于 window 对象是一个全局对象,因此在使用 window.screen 时可以省略 window 前缀,例如 window.screen.width 可以简写为 screen.width。

1. screen 对象中的属性

下表中列举了 JavaScript screen 对象中常用的属性及其描述:

属性 说明
availTop 返回屏幕上方边界的第一个像素点(大多数情况下返回 0)
availLeft 返回屏幕左边边界的第一个像素点(大多数情况下返回 0)
availHeight 返回屏幕的高度(不包括 Windows 任务栏)
availWidth 返回屏幕的宽度(不包括 Windows 任务栏)
colorDepth 返回屏幕的颜色深度(color depth),根据 CSSOM(CSS 对象模型)视图,为兼容起见,该值总为 24。
height 返回屏幕的完整高度
pixelDepth 返回屏幕的位深度/色彩深度(bit depth),根据 CSSOM
width 返回屏幕的完整宽度
orientation 返回当前屏幕的方向

示例代码如下:

document.write(screen.availTop + "<br>");   // 输出:0
document.write(screen.availLeft + "<br>");  // 输出:0
document.write(screen.availHeight + "<br>");// 输出:1050
document.write(screen.availWidth + "<br>"); // 输出:1920
document.write(screen.height + "<br>");     // 输出:1080
document.write(screen.width + "<br>");      // 输出:1920
document.write(screen.colorDepth + "<br>"); // 输出:24
document.write(screen.pixelDepth + "<br>"); // 输出:24
console.log(screen.orientation);            // 输出:ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}

2. 获取屏幕的宽度和高度

您可以使用 screen 对象的 width 和 height 属性来获取用户计算机屏幕的宽度和高度(单位为像素),示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <button type="button" onclick="getResolution();">获取屏幕的宽度和高度</button>
    <script type="text/javascript">
        function getResolution() {
            alert("您计算机屏幕的尺寸为:" + screen.width + "x" + screen.height);
        }
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

3. 获取屏幕的颜色深度

您可以使用 screen 对象的 colorDepth 属性来获取用户计算机屏幕的颜色深度,示例代码如下:

提示:颜色深度表示屏幕能够产生多少中颜色,例如,颜色深度为 8 的屏幕可以产生 256 种颜色(即 28),目前大部分屏幕的颜色深度为 24 或 32,一些较旧的显示器的颜色深度为 8 或 16。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <button type="button" onclick="getColorDepth();">获取颜色深度</button>
    <script type="text/javascript">
        function getColorDepth() {
            alert("您计算机屏幕的颜色深度为:" + screen.colorDepth);
        }
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

JS Location对象:获取URL

JavaScript location 对象中包含了有关当前页面链接(URL)的信息,例如当前页面的完整 URL、端口号等,我们可以通过 window 对象中的 location 属性来获取 location 对象。由于 window 对象是一个全局对象,因此在使用 window.location 时可以省略 window 前缀,例如 window.location.href 可以简写为 location.href

1. location 对象中的属性

下表中列举了 JavaScript location 对象中常用的属性及其描述:

属性 描述
hash 返回一个 URL 中锚的部分,例如:http://c.biancheng.net#js 中的 #js。
host 返回一个 URL 的主机名和端口号,例如 http://c.biancheng.net:8080。
hostname 返回一个 URL 的主机名,例如 http://c.biancheng.net。
href 返回一个完整的 URL,例如 http://c.biancheng.net/javascript/location-object.html。
pathname 返回一个 URL 中的路径部分,开头有个 /
port 返回一个 URL 中的端口号,如果 URL 中不包含明确的端口号,则返回一个空字符串 ' '
protocol 返回一个 URL 协议,即 URL 中冒号 : 及其之前的部分,例如 http: 和 https:。
search 返回一个 URL 中的查询部分,即 URL 中 ? 及其之后的一系列查询参数。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <a href="http://c.biancheng.net:8080/javascript/location-objcet.html?course=javascript&title=location#content" id="url"></a>
    <script type="text/javascript">
        var url = document.getElementById('url');
        document.write("<b>hash:</b>" + url.hash + "<br>");
        document.write("<b>host:</b>" + url.host + "<br>");
        document.write("<b>hostname:</b>" + url.hostname + "<br>");
        document.write("<b>href:</b>" + url.href + "<br>");
        document.write("<b>pathname:</b>" + url.pathname + "<br>");
        document.write("<b>port:</b>" + url.port + "<br>");
        document.write("<b>protocol:</b>" + url.protocol + "<br>");
        document.write("<b>search:</b>" + url.search + "<br>");
    </script>
</body>
</html>

运行结果如下:

hash:#content
host:c.biancheng.net:8080
hostname:c.biancheng.net
href:http://c.biancheng.net:8080/javascript/location-objcet.html?course=javascript&title=location#content
pathname:/javascript/location-objcet.html
port:8080
protocol:http:
search:?course=javascript&title=location

2. location 对象中的方法

下表中列举了 JavaScript location 对象中常用的方法及其描述:

方法 说明
assign() 加载指定的 URL,即载入指定的文档。
reload() 重新加载当前 URL。
replace() 用指定 URL 替换当前的文档,与 assign() 方法不同的是,使用 replace()
toString() 与 href 属性的效果相同,以字符串的形式返回当前完整的 URL。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <a href="http://c.biancheng.net:8080/javascript/location-objcet.html?course=javascript&title=location#content" id="url"></a>
    <button onclick="myAssign()">assign()</button>
    <button onclick="myReload()">reload()</button>
    <button onclick="myReplace()">replace()</button>
    <button onclick="myToString()">toString()</button>
    <script type="text/javascript">
        var url = 'http://c.biancheng.net';
        function myAssign(){
            location.assign(url);
        }
        function myReload(){
            location.reload();
        }
        function myReplace(){
            location.replace(url);
        }
        function myToString(){
            var url = document.getElementById('url');
            var str = url.toString();
            alert(str);
        }
    </script>
</body>
</html>

JS History对象:获取浏览历史

JavaScript history 对象中包含了用户在浏览器中访问过的历史记录,其中包括通过浏览器浏览过的页面,以及当前页面中通过加载的页面。我们可以通过 window 对象中的 history 属性来获取 history 对象,由于 window 对象是一个全局对象,因此在使用window.history 时可以省略 window 前缀,例如 window.history.go() 可以简写为 history.go()。

1. history 对象中的属性

下表中列举了 JavaScript history 对象中常用的属性及其描述:

属性 说明
length 返回浏览历史的数目,包含当前已经加载的页面。
scrollRestoration 利用浏览器特性,使我们在返回上一页或者下一页时,将页面滚动到之前浏览的位置,该属性有两个值,分别是 auto(表示滚动)与 manual(表示不滚动)。
state 返回浏览器在当前 URL 下的状态信息,如果没有调用过 pushState() 或 replaceState() 方法,则返回默认值 null。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        document.write(history.length + "<br>");
        document.write(history.scrollRestoration + "<br>");
        document.write(history.state + "<br>");
    </script>
</body>
</html>

运行结果如下:

5
auto
null

2. history 对象中的方法

下表中列举了 JavaScript history 对象中常用的方法及其描述:

方法 说明
back() 参照当前页面,返回历史记录中的上一条记录(即返回上一页),您也可以通过点击浏览器工具栏中的 ← 按钮来实现同样的效果。
forward() 参照当前页面,前往历史记录中的下一条记录(即前进到下一页),您也可以通过点击浏览器工具栏中的 → 按钮来实现同样的效果。
go() 参照当前页面,根据给定参数,打开指定的历史记录,例如 -1 表示返回上一页,1 表示返回下一页。
pushState() 向浏览器的历史记录中插入一条新的历史记录。
replaceState() 使用指定的数据、名称和 URL 来替换当前历史记录。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <button onclick="myBack()">back()</button>
    <button onclick="myForward()">forward()</button>
    <button onclick="myGo()">go()</button>
    <button onclick="myPushState()">pushState()</button>
    <button onclick="myReplaceState()">replaceState()</button>
    <script type="text/javascript">
        function myBack(){
            history.back();
        }
        function myForward(){
            history.forward();
        }
        function myGo(){
            var num = prompt('请输入一个整数', '1');
            history.go(num);
        }
        function myPushState(){
            var state = { 'page_id': 1, 'user_id': 5 }
            var title = 'JavaScript'
            var url = 'index.html'
            history.pushState(state, title, url)
            console.log(history.state);
        }
        function myReplaceState(){
            var state = { 'page_id': 3, 'user_id': 5 }
            var title = 'history'
            var url = 'index.html'
            history.replaceState(state, title, url)
            console.log(history.state);
        }
    </script>
</body>
</html>

JS 定时器:setTimeout和setInterval

JavaScript 定时器,有时也称为“计时器”,用来在经过指定的时间后执行某些任务,类似于我们生活中的闹钟。

在 JavaScript 中,我们可以利用定时器来延迟执行某些代码,或者以固定的时间间隔重复执行某些代码。例如,您可以使用定时器定时更新页面中的广告或者显示一个实时的时钟等。

JavaScript 中提供了两种方式来设置定时器,分别是 setTimeout() 和 setInterval(),它们之间的区别如下:

方法 说明
setTimeout() 在指定的时间后(单位为毫秒),执行某些代码,代码只会执行一次
setInterval() 按照指定的周期(单位为毫秒)来重复执行某些代码,定时器不会自动停止,除非调用 clearInterval() 函数来手动停止或着关闭浏览器窗口

1. setTimeout()

JS setTimeout() 函数用来在指定时间后执行某些代码,代码仅执行一次。

JS setTimeout() 函数的语法格式如下:

setTimeout(function[, delay, arg1, arg2, ...]);
setTimeout(function[, delay]);
setTimeout(code[, delay]);

参数说明如下:

  • function:一个函数(通常使用匿名函数),其中定义了定时器中要执行的代码;
  • code:字符串类型的代码,这些代码会在定时器到期后被编译执行,出于安全考虑不建议使用;
  • delay:可选参数,定时器在执行的其中代码之前,要等待的时间,单位为毫秒(1秒 = 1000毫秒),如果省略此参数,则表示立即执行;
  • arg1、arg2、…、argN:要传递给函数的参数。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script type="text/javascript">
        var myFun = function (str = 'JavaScript'){
            document.write(str + "<br>");
        };
        setTimeout(myFun, 500, 'Hello');
        setTimeout(myFun, 1000);
        setTimeout(function(){
            document.write("定时器<br>");
        }, 1500)
        setTimeout("document.write(\"setTimeout()\")", 2000);
    </script>
</body>
</html>

运行上面的代码,会间隔 500 毫秒,依次输出下面的内容:

Hello
JavaScript
定时器
setTimeout()

2. setInterval()

JS setInterval() 函数可以定义一个能够重复执行的定时器,每次执行需要等待指定的时间间隔。

JS setInterval() 函数的语法格式如下:

setInterval(function, delay, [arg1, arg2, ...]);
setInterval(code, delay);

参数说明如下:

  • function:一个函数(通常使用匿名函数),其中定义了定时器中要执行的代码;
  • code:字符串类型的代码,这些代码会在定时器到期后被编译执行,出于安全考虑不建议使用;
  • delay:可选参数,定时器在执行的其中代码之前,要等待的时间,单位为毫秒(1秒 = 1000毫秒),如果省略此参数,则表示立即执行;
  • arg1、arg2、…、argN:要传递给函数的参数。

提示:通过 setInterval() 函数定义的定时器不会自动停止,除非调用 clearInterval() 函数来手动停止或着关闭浏览器窗口。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <p id="one"></p>
    <p id="two"></p>
    <script type="text/javascript">
        var num = 1;
        var myFun = function (){
            document.getElementById('one').innerHTML += num + "&nbsp;";
            num ++;
        };
        setInterval(myFun, 500);
        setInterval(function(){
            var d = new Date();
            document.getElementById('two').innerHTML = d.toLocaleTimeString();
        }, 1000);
    </script>
</body>
</html>

运行结果如下:

1 2 3 4 5 6 7 8 9
下午4:01:13

3. JS 取消定时器

当使用 setTimeout() 或 setInterval() 设置定时器时,这两个方法都会产生一个定时器的唯一 ID,ID 为一个正整数值,也被称为“定时器标识符”,通过这个 ID,我们可以清除 ID 所对应的定时器。

我们可以借助 clearTimeout() 或 clearInterval() 函数来分别清除由 setTimeout() 或 setInterval() 函数创建的定时器。调用 clearTimeout() 或 clearInterval() 函数需要提供定时器的唯一 ID 作为参数,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <p>当前时间为:<span id="clock"></span></p>
    <button onclick="stopClock(this);">停止</button><hr>
    <button onclick="delayedAlert(this);">2秒后弹出一个提示框</button>
    <button onclick="clearAlert();">取消</button>
    <script type="text/javascript">
        var intervalID;
        function showTime() {
            var d = new Date();
            document.getElementById("clock").innerHTML = d.toLocaleTimeString();
        }
        function stopClock(e) {
            clearInterval(intervalID);
            e.setAttribute('disabled', true)
        }
        intervalID = setInterval(showTime, 1000);
        var timeoutID;
        var that;
        function delayedAlert(e) {
            that = e;
            timeoutID = setTimeout(showAlert, 2000);
            e.setAttribute('disabled', true)
        }
        function showAlert() {
            alert('这是一个提示框。');
            that.removeAttribute('disabled');
        }
        function clearAlert() {
            clearTimeout(timeoutID);
            that.removeAttribute('disabled');
        }
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

JS try catch用法:异常处理

在编程中,有时代码并不会像我们预期的那样运行,会遇到各式各样的错误,例如代码中使用了错误的符号、调用未定义的方法、网络错误、读取不存在的文件、没有操作权限等。

根据类型的不同,JavaScript 编程中的错误大致可以分为以下三种类型:

  • 语法错误:也称为解析错误,一般是因为代码存在某些语法错误引起的。当发生语法错误时,代码会停止运行;
  • 运行时错误:也称为异常,发生在程序运行期间,例如调用未定义的方法、读取不存在的文件等,发生运行时错误也会终止代码运行;
  • 逻辑错误:是最难发现的一种错误,逻辑错误通常是因为代码存在瑕疵,导致程序输出意外的结果或终止运行。

1. 错误和异常的区别

错误(Error)是在代码运行之前出现的,在运行 JavaScript 程序之前,JavaScript 解释器会先对代码进行检查,如果代码有误,例如某些语法错误,浏览器就会报出相应的错误,只有将错误修正后,代码才能运行。

异常(Exception)是在代码运行中出现的,例如调用某个未定义的方法、读取不存在的文件等。在出现异常之前,代码的运行并不受影响,当出现异常时,会在浏览器控制台输出错误信息,并终止程序的运行。

2. JS 异常处理

异常处理的目的是捕捉产生异常的代码,使整个程序不会因为异常而终止运行。在 JavaScript 中,您可以使用 try catch 语句来捕获异常,并做出相应处理,语法格式如下:

try {
    // 可能会发生异常的代码
} catch(error) {
    // 发生异常时要执行的操作
}

我们可以将任何可能发生异常的代码放到 try 语句块中,并在 catch 语句块中定义处理异常的方法。如果 try 语句块中的代码发生错误,代码会立即从 try 语句块跳转到 catch 语句块中,如果 try 语句块中代码没有发生错误,就会忽略 catch 语句块中的代码。

JS 示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script>
        try {
            var title = "JavaScript";
            document.write(title);
            // 调用一个未定义的变量
            document.write(str);
            // 若发生错误,则不会执行以下行
            alert("所有语句都已成功执行。");
        } catch(error) {
            // 处理错误
            alert("错误信息: " + error.message);
        }
        // 继续执行下面的代码
        document.write("<p>Hello World!</p>");
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述
当 try 语句块中的代码出现异常时,会创建并抛出一个 Error 对象(例如上面代码内 catch(error) 中的 error),对象中包含两个属性,如下所示:

  • name:错误的类型;
  • message:对错误的描述信息。

3. JS try catch finally 语句

在 try catch 语句的后面,还可以添加一个 finally 语句块,无论 try 语句块中的代码是否发生错误,finally 语句中的代码都会执行。示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script>
        // 接收用户输入的参数
        var num = prompt("输入一个 0 到 100 的数字");
        // 获取当前时间
        var start = Date.now();
        try {
            if(num > 0 && num <= 100) {
                console.log(Math.pow(num, num)); // 指数幂的基
            } else {
                console.log("输入的值无效!");
            }
        } catch(e) {
            console.log(e.message);
        } finally {
            // 显示执行代码所用的时间
            console.log("代码执行花费了:" + (Date.now() - start) + "ms");
        }
    </script>
</body>
</html>

假如我们输入一个小于 100 的数字,例如 88,运行结果如下:

1.3015928349429721e+171
代码执行花费了:0ms

假如我们输入一个大于 100 的数字,例如 123,运行结果如下:

输入的值无效!
代码执行花费了:0ms

4. JS 抛出错误

JavaScript 中,不仅可以依赖 JavaScript 解析器来自动抛出错误,还可以手动抛出错误。抛出错误需要使用 throw 语句,语法格式如下:

throw expression;

其中 expression 为要抛出的异常,可以是任何类型的值,例如对象、字符串、数组等,推荐使用对象类型。

JavaScript 中内置了一个 Error() 函数来创建要抛出的错误对象,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script>
        function squareRoot(number) {
            // 如果数字为负数,则抛出错误
            if(number < 0) {
                throw new Error("抱歉,无法计算负数的平方根!");
            } else {
                console.log(Math.sqrt(number));
            }
        }
        try {
            squareRoot(16);
            squareRoot(625);
            squareRoot(-9);
            squareRoot(100);
            // 若抛出错误,则不会执行下面的行
            console.log("所有函数都执行成功。");
        } catch(e) {
            // 处理错误
            console.log(e.message);
        }
    </script>
</body>
</html>

运行结果如下:

4
25
抱歉,无法计算负数的平方根!

5. JS 错误类型

前面我们提到,当 try 语句块中的代码出现错误时,会创建并抛出一个 Error 对象,对象中包含错误类型和错误描述两个属性。

发生不同的错误,会返回不同的错误类型,JavaScript 中支持以下几种错误类型:

错误类型 说明
EvalError 使用 eval() 函数时发出错误,会抛出该错误
InternalError 由 JavaScript 引擎内部错误导致的异常,会抛出该错误
RangeError 范围错误,当使用了超出允许范围的数值时,会抛出该错误
SyntaxError 语法错误,当代码中存在任何语法错误时,会抛出该错误
TypeError 类型错误,当使用的值不是预期类型时,会抛出该错误,例如对数字调用字符串方法,对字符串调用数组方法等
URIError URI 错误,当使用 URI 相关函数但传入 URI 参数时,会抛出该错误
ReferenceError 参数错误,当尝试使用未定义的变量、函数、对象时,会抛出该错误

JS 表单验证

表单是 Web 应用(网站)的重要组成部分,通过表单可以收集用户提交的信息,例如姓名、邮箱、电话等。由于用户在填写这些信息时,有可能出现一些错误,例如输入手机号时漏掉了一位、在输入的内容前后输入空格、邮箱的格式不正确等。为了节省带宽同时避免这些问题对服务器造成不必要的压力,我们可以使用 JavaScript 在提交数据之前对数据进行检查,确认无误后再发送到服务器。

使用 JavaScript 来验证提交数据(客户端验证)比将数据提交到服务器再进行验证(服务器端验证)用户体验要更好,因为客户端验证发生在用户浏览器中,无需向服务器发送请求,所以速度更快,而服务器端验证,需要先将数据提交到服务器,然后服务器再将结果返回给浏览器,用户需要等待服务器响应结果才能知道哪里出了问题。

注意:虽然客户端验证更快,但是客户端验证并不能替代服务器端验证。在开发过程中,无论是否进行客户端验证,都需要在服务器端对于用户提交的数据进行验证,因为用户可以在浏览器中禁用 JavaScript。

1. 使用 JavaScript 进行表单验证

表单验证通常由两个部分组成:

  • 必填字段验证:确保必填的字段都被填写;
  • 数据格式验证:确保所填内容的类型和格式是正确的、有效的。

2. 必填字段验证

必填字段验证在用户注册时比较常见,通过必填字段验证,能够确保表单中的必填字段都被填写,例如用户名、密码、邮箱等。

实现必填字段验证非常简单,只需要通过程序来检查必填表单元素的值是否为空即可,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style>
        .error{
            color: red;
        }
        label{
            display: inline-block;
            width: 70px;
            text-align: right;
        }
    </style>
</head>
<body>
    <form onsubmit="return validateForm()" action="" method="post">
        <fieldset>
            <legend>注册:</legend>
            <div class="row">
                <label>用户名:</label>
                <input type="text" name="name">
                <span class="error" id="nameErr"></span>
            </div>
            <div class="row">
                <label>密码:</label>
                <input type="password" name="pwd">
                <span class="error" id="pwdErr"></span>
            </div>
            <div class="row">
                <label>Email:</label>
                <input type="text" name="email">
                <span class="error" id="emailErr"></span>
            </div>
            <div class="row">
                <label>手机号:</label>
                <input type="text" name="mobile" maxlength="11">
                <span class="error" id="mobileErr"></span>
            </div>
            <div class="row">
                <label>验证码:</label>
                <input type="text" name="captcha" maxlength="4"><span id="captcha" onclick="getCaptcha()"></span>
                <span class="error" id="captchaErr"></span>
            </div>
            <div class="row">
                <input type="submit" value="注册">
            </div>
        </fieldset>
    </form>
    <script>
        var captcha = getCaptcha(); // 生成验证码
        // 清空 input 标签后的提示信息
        var tags = document.getElementsByTagName('input');
        for (var i = 0; i < tags.length; i++) {
            tags[i].onchange = function(){
                var idname = this.name + "Err";
                document.getElementById(idname).innerHTML = '';
            }
        }
        // 显示错误消息
        function printError(elemId, hintMsg) {
            document.getElementById(elemId).innerHTML = hintMsg;
        }
        // 验证表单数据
        function validateForm() {
            // 获取表单元素的值
            var name = document.querySelector("input[name='name']").value;
            var pwd = document.querySelector("input[name='pwd']").value;
            var email = document.querySelector("input[name='email']").value;
            var mobile = document.querySelector("input[name='mobile']").value;
            var captcha = document.querySelector("input[name='captcha']").value;
                  
            if(name == "" || name == null){
                printError("nameErr", "用户名不能为空");
                return false;
            }
            if(pwd == "" || pwd == null){
                printError("pwdErr", "密码不能为空");
                return false;
            }
            if(email == "" || email == null){
                printError("emailErr", "邮箱不能为空");
                return false;
            }
            if(mobile == "" || mobile == null){
                printError("mobileErr", "手机号不能为空");
                return false;
            }
            if(captcha == "" || captcha == null){
                printError("captchaErr", "验证码不能为空");
                return false;
            }
        }
        // 获取验证码
        function getCaptcha(){
            var cap = Math.floor(Math.random()*10000).toString();
            if(cap.length != 4) cap += "0";
            captcha = cap;
            document.getElementById("captcha").innerHTML = cap;
        }
    </script>
</body>
</html>

运行结果如下:
在这里插入图片描述

3. 数据格式验证

数据格式验证就是通过正则表达式来验证用户所填的数据,是否符合要求,以邮箱地址为例,正确的邮箱地址中要包含一个 @ 和一个 . ,而且 @ 不能是邮箱地址的第一个字符,. 要出现在 @ 之后。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style>
        .error{
            color: red;
        }
        label{
            display: inline-block;
            width: 70px;
            text-align: right;
        }
    </style>
</head>
<body>
    <form onsubmit="return validateForm()" action="" method="post">
        <fieldset>
            <legend>注册:</legend>
            <div class="row">
                <label>用户名:</label>
                <input type="text" name="name">
                <span class="error" id="nameErr"></span>
            </div>
            <div class="row">
                <label>密码:</label>
                <input type="password" name="pwd">
                <span class="error" id="pwdErr"></span>
            </div>
            <div class="row">
                <label>Email:</label>
                <input type="text" name="email">
                <span class="error" id="emailErr"></span>
            </div>
            <div class="row">
                <label>手机号:</label>
                <input type="text" name="mobile" maxlength="11">
                <span class="error" id="mobileErr"></span>
            </div>
            <div class="row">
                <label>验证码:</label>
                <input type="text" name="captcha" maxlength="4"><span id="captcha" onclick="getCaptcha()"></span>
                <span class="error" id="captchaErr"></span>
            </div>
            <div class="row">
                <input type="submit" value="注册">
            </div>
        </fieldset>
    </form>
    <script>
        var capCode = getCaptcha(); // 生成验证码
        console.log(capCode);
        // 清空 input 标签后的提示信息
        var tags = document.getElementsByTagName('input');
        for (var i = 0; i < tags.length; i++) {
            tags[i].onchange = function(){
                var idname = this.name + "Err";
                document.getElementById(idname).innerHTML = '';
            }
        }
        // 显示错误消息
        function printError(elemId, hintMsg) {
            document.getElementById(elemId).innerHTML = hintMsg;
        }
        // 验证表单数据
        function validateForm() {
            // 获取表单元素的值
            var name = document.querySelector("input[name='name']").value;
            var pwd = document.querySelector("input[name='pwd']").value;
            var email = document.querySelector("input[name='email']").value;
            var mobile = document.querySelector("input[name='mobile']").value;
            var captcha = document.querySelector("input[name='captcha']").value;
                  
            if(name == "" || name == null){
                printError("nameErr", "用户名不能为空");
                return false;
            }
            if(pwd == "" || pwd == null){
                printError("pwdErr", "密码不能为空");
                return false;
            }
            if(email == "" || email == null){
                printError("emailErr", "邮箱不能为空");
                return false;
            } else {
                var regex = /^\S+@\S+\.\S+$/;
                if(regex.test(email) === false) {
                    printError("emailErr", "请输入正确的邮箱地址");
                    return false;
                }
            }
            if(mobile == "" || mobile == null){
                printError("mobileErr", "手机号不能为空");
                return false;
            } else {
                var regex = /^[1]\d{10}$/;
                if(regex.test(mobile) === false) {
                    printError("mobileErr", "您输入的手机号码有误");
                    return false;
                }
            }
            if(captcha == "" || captcha == null){
                printError("captchaErr", "验证码不能为空");
                return false;
            } else {
                console.log(capCode);
                console.log(captcha);
                if(capCode != captcha){
                    printError("captchaErr", "验证码有误");
                    return false;
                }
            }
        }
        // 获取验证码
        function getCaptcha(){
            var cap = Math.floor(Math.random()*10000).toString();
            if(cap.length != 4) cap += "0";
            document.getElementById("captcha").innerHTML = cap;
            return capCode = cap;
        }
    </script>
</body>
</html>

运行结果如下:
在这里插入图片描述

JS 动画效果的实现

在学习 CSS 时我们知道,通过 CSS 可以实现简单的动画效果,但对于比较复杂的动画,使用 CSS 实现起来就会比较麻烦。除了可以使用 CSS 来实现外,也可以使用 JavaScript 来实现。JavaScript 动画主要是通过修改元素样式来实现的,能够实现许多 CSS 动画所不能实现的效果,例如暂停、回放等。

与 CSS 动画相比,JavaScript 动画具有以下特点:

  • JavaScript 动画控制能力更强,可以在动画播放过程中对动画进行控制,例如开始、暂停、回放、终止、取消等;
  • JavaScript 动画的效果比 CSS 动画更丰富,比如曲线运动,冲击闪烁,视差滚动等效果,只有 JavaScript 动画才能完成;
  • CSS 动画有兼容性问题,而 JavaScript 大多时候没有兼容性问题。

JavaScript 主要通过代码修改 DOM 元素来实现动画的,并且可以配合定时器来实现循环播放,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #box {
            width: 200px;
            height: 200px;
            margin-top: 10px;
            background: rgb(43, 221, 255);
            position: relative;
            left: -200px;
            top: 0;
        }
        #box span {
            width: 20px;
            background: rgb(255, 119, 157);
            position: absolute;
            left: 200px;
            top: 75px;
            color: #fff;
            text-align: center;
            cursor: pointer;
            padding: 5px 1px 5px 0;
            border-radius: 0 5px 5px 0;
        }
        #box span:hover {
            background: rgb(255, 84, 137);
        }
    </style>   
</head>
<body>
    <div id="box">
        <span id="share">分享</span>
    </div>
    <script>
        window.onload = function () {
            //动画
            var div = document.getElementById("box");
            var timer = null;
            div.onmouseover = function () {
                startMove(0);
            };
            div.onmouseout = function () {
                startMove(-200);
            };
            function startMove(targetPosition) {
                clearInterval(timer);
                var speed = 0;
                if (targetPosition < 0) {
                    speed = -10;
                } else {
                    speed = 10;
                }
                timer = setInterval(function () {
                    if (div.offsetLeft == targetPosition) {
                        clearInterval(timer);
                    } else {
                        div.style.left = div.offsetLeft + speed + 'px';
                    }
                }, 17);
            }
        };
    </script>
</body>
</html>

运行结果如下:
在这里插入图片描述

提示:如今,大多数显示器的刷新率为 60HZ,为了实现更加平滑的动画效果,使用定时器的最佳循环间隔约为 17ms。

下面再通过一个示例来演示如何创建 JavaScript 动画,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        * {
            margin: 0 auto;
            padding: 0;
        }
        ul {
            list-style: none;
        }
        #view {
            position: relative;
            width: 320px;
            height: 120px;
            border: 10px solid #bc8f8f;
            overflow: hidden;
            margin-top: 5px;
        }
        #img_list {
            position: absolute;
            width: 960px;
        }
        #img_list li {
            float: left;
            width: 320px;
            height: 120px;
        }
    </style>
</head>
<body>
    <div id="view">
        <ul id="img_list">
            <li style="background-color: #87ceeb;"></li>
            <li style="background-color: #ff69b4;"></li>
            <li style="background-color: #98fb98;"></li>
        </ul>
    </div>
    <script type="text/javascript">
        var img_list = document.getElementById('img_list');
        setInterval(function() {
            for (var i = 0; i <= 100; i++) {
                (function(pos) {
                    setTimeout(function() {
                        img_list.style.left = - (pos / 100) * 320 + 'px';
                    }, (pos + 1) * 10)
                })(i)
            }
            var current = img_list.children[0];
            setTimeout(function() {
                img_list.appendChild(current);
                img_list.style.left = '0px';
            }, 1100);
        }, 2000);
    </script>
</body>
</html>

运行结果如下:
在这里插入图片描述

JS 调试(Debug)教程

在 JavaScript 开发过程中,代码可能存在一些语法或者逻辑上的错误,导致程序不能得到我们想要的结果,这时就需要我们找到并修复这些错误,我们将查找和修复错误的过程称为调试或代码调试。

调试是程序开发过程中必不可少的一个环节,熟练掌握各种调试技巧,能在我们的工作中起到事半功倍的效果。

在前端开发中,想要快速定位错误,可以借助浏览器内置的调试工具(控制台),通常按键盘上的 F12 就能启动,借助调试工具我们不仅可以很轻松的找到代码出错的位置,还可以通过设置断点(代码执行到断点处会暂停),来检查代码执行过程中变量的变化。

1. 控制台

控制台中能够显示代码中的语法错误和运行时错误,其中包括错误类型、错误描述以及错误出现的位置(即错误所在的行),如下图所示:
在这里插入图片描述
在这里插入图片描述
借助控制台提供的信息,我们可以轻松的定位代码中的错误,不过有一点需要注意,就是控制台提供的错误信息不一定百分之百正确,因为某些错误可能是由于另外一个错误直接或间接引起的,所以控制台提示有错误的地方不一定真有问题。

2. 如何调试 JavaScript 代码

有多种方法可以调试 JavaScript 代码,最简单的方法就是使用 console.log()、document.write()、alert() 等方法来打印程序中各个变量、对象、表达式的值,以确保程序每个阶段的运行结果都是正确的,推荐使用 console.log(),如下例所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <div id="box"></div>
    <script>
        var box = document.getElementById('box');
        console.log(box);
        var a = 'Hello', b = 'JavaScript';
        var c = a + ' ' + b;
        console.log(c);
        box.innerHTML = c;
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述
使用这种方法调试代码有一个弊端,那就是这些输出语句并不是代码中需要的,虽然它们不会影响代码的运行,但是为了代码更加整洁,在调试完程序后我们需要手动清理干净。

3. 断点调试

断点是浏览器内置调试工具的重要功能之一,通过设置断点可以让程序在我们需要的地方中断(暂停),从而方便我们对该处代码进行分析和逻辑处理。以 Chrome 浏览器为例,要进行断点调试首先需要打开浏览器内置的开发者工具(按 F12 或者单击鼠标右键,在弹出的菜单中选择“检查”),然后在找到并选择“Sources”,如下图所示:
在这里插入图片描述

1) 找到要调试的文件

打开调试工具后,需要在工具的左侧找到要调试的文件并单击打开该文件,如下图所示:

在这里插入图片描述

2) 打断点

给代码打断点非常简单,只需要在单击要调试代码前面的行号即可,若行号被标记为蓝色,则说明已经成功打了断点,如下图所示(在代码的第 11 行和第 14 行打了断点):
在这里插入图片描述

3) 断点调试

打好断点后,刷新页面即可进入调试模式,代码执行到断点的位置会暂停,此时我们可以点击页面中的箭头会按 F8 来使代码继续执行到下个断点,如下图所示:
在这里插入图片描述

调试过程中,会在调试工具的最右侧的 Scope 栏显示一些数据。此外,还可以在最右侧的 Watch 栏中录入要调试的变量名,这样在调试过程中就能实时看到代码运行中变量的变化。

4) 逐语句执行

在调试过程中,我们还可以选择让代码逐句执行,只需要点击下图所示的按钮,或者按 F10 即可:
在这里插入图片描述
逐句执行配合在 Watch 栏中录入要调试的变量,能够更清晰的看到变量在代码运行过程中的变化:
在这里插入图片描述

4. debugger关键字

除了可以借助浏览器的调试工具来给代码设置断点外,也可以使用 debugger 关键字在代码中设置断点(类似于 PHP 中的 die 和 exit),效果与在调试工具中设置断点是一样的,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <div id="box"></div>
    <script>
        var x = 15 * 5;
        debugger;
        document.getElementById('box').innerHTML = x;
    </script>
</body>
</html>

运行上面的代码,浏览器会自动进入调试模式,并在执行到 debugger 关键字时(代码第 12 行)暂停。

JS 闭包的原理和作用

闭包(closures)是 Javascript 语言的一个难点,也是它的特色,很多高级应用都是依靠闭包实现的。闭包与变量的作用域以及变量的生命周期密切相关,本节我们就来简单介绍一下。

1. 什么是闭包

所谓闭包,指的就是一个函数。当两个函数彼此嵌套时,内部的函数就是闭包。

因为在 JavaScript 中,函数属于对象,对象又是属性的集合,而属性的值又可以是对象,所以我们可以在函数内部再定义函数。例如在函数 A 中定义了函数 B,然后在函数外部调用函数 B,这个过程就是闭包。

闭包的形成条件是内部函数需要通过外部函数 return 给返回出来,如下例所示:

function funOne(){    // 外部函数
    var num = 0;      // 局部变量
    function funTwo(){   // 内部函数
        num++;                 
        return num;
    }
    return funTwo;
}
var fun = funOne();             // 返回函数 funTwo

以上代码就构成了一个闭包,其实就是函数 fun。

2. 闭包的用途

在介绍闭包的作用之前,我们先来了解一下 JavaScript 中的 GC(垃圾回收)机制。

在 JavaScript 中,如果一个对象不再被引用,那么这个对象就会被 GC 回收,否则这个对象会一直保存在内存中。在上面的例子中,内部函数 funTwo() 定义在外部函数 funOne() 中,因此 funTwo() 依赖于 funOne(),而全局变量 fun 又引用了 funTwo(),所以 funOne() 间接的被 fun 引用。因此 funOne() 不会被 GC 回收,会一直保存在内存中,如下例所示:

function funOne(){
    var num = 0;
    function funTwo(){
        num++;
        console.log(num);
    }
    return funTwo;
}
var fun = funOne();
fun();      // 输出:1
fun();      // 输出:2
fun();      // 输出:3
fun();      // 输出:4

num 是外部函数 funOne() 中的一个变量,它的值在内部函数 funTwo() 中被修改,函数 funTwo() 每执行一次就会将 num 加 1。根据闭包的特点,函数 funOne() 中的变量 num 会一直保存在内存中。

当我们需要在函数中定义一些变量,并且希望这些变量能够一直保存在内存中,同时不影响函数外的全局变量时,就可以使用闭包。

3. 闭包的高级用法

上面介绍的是闭包最原始的写法,在实际开发中,通常会将闭包与匿名函数结合使用,如下例所示:

var funOne = (function(){
    var num = 0;
    return function(){
        num++;
        return num;
    }
})();
console.log(funOne());      // 输出:1
console.log(funOne());      // 输出:2
console.log(funOne());      // 输出:3

此外,同一个闭包机制可以创建多个闭包函数出来,它们彼此没有联系,都是独立的,如下例所示:

function funOne(i){
    function funTwo(){
        console.log('数字:' + i);
    }
    return funTwo;
};
var fa = funOne(110);
var fb = funOne(111);
var fc = funOne(112);
fa();       // 输出:数字:110
fb();       // 输出:数字:111
fc();       // 输出:数字:112

JS严格模式(use strict)

由于 JavaScript 语法不够严谨,一直被人们所诟病,例如在使用一个变量时,可以不使用 var 关键字来提前声明(例如:url = 'https://www.csdn.net/';),此时 JavaScript 解释器会自动为您创建这个变量。为了使代码更加严谨,JavaScript 中引入了严格模式,一旦使用了严格模式,将不再允许使用那些不严谨的语法。

1. 什么是严格模式

严格模式是在 ECMAScript5(ES5)中引入的,在严格模式下,JavaScript 对语法的要求会更加严格,一些在正常模式下能够运行的代码,在严格模式下将不能运行。

添加严格模式,主要有以下几个目的:

  • 消除 JavaScript 语法中一些不合理、不严谨的地方;
  • 消除代码中一些不安全的地方,保证代码的安全运行;
  • 提高 JavaScript 程序的运行效率;
  • 为以后新版本的 JavaScript 做好铺垫。

目前,主流浏览器包括 IE10 及其之后的版本都已支持严格模式,JavaScript 正在向着更合理、更安全、更严谨的方向发展。

2. 启用严格模式

要启用严格模式,您只需要在 JavaScript 脚本的开头添加 “use strict”; 或 ‘use strict’; 指令即可,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script>
        "use strict";
        x = 'https://www.csdn.net/'; // 此处报错:Uncaught ReferenceError: x is not defined at index.html:11
        console.log(x);
    </script>
</body>
</html>

如果将 “use strict”; 指令添加到 JavaScript 程序的第一行,则表示整个脚本都会处于严格模式。如果在函数的第一行代码中添加 “use strict”;,则表示只在该函数中启用严格模式。如下例所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <script>
        x = 'https://www.csdn.net/';
        console.log(x);
        function sayHello(){
            'use strict';
            str = 'welcome https://www.csdn.net/'; // 调用 sayHello() 函数在此处报错:Uncaught ReferenceError: str is not defined at sayHello (index.html:14) at index.html:17
            console.log(str);
        }
        sayHello();
    </script>
</body>
</html>

注意:“use strict”; 或 ‘use strict’; 指令只有在整个脚本第一行或者函数第一行时才能被识别,除了 IE9 以及更低的版本外,所有的浏览器都支持该指令。

3. 严格模式中的变化

相对于普通模式来说,严格模式对 JavaScript 的语法都做了一些改变。
1、不允许使用未声明的变量
普通模式下,如果一个变量还没有声明,就直接拿来赋值,JavaScript 解释器会自动为您创建这个变量。而在严格模式下,则不允许这么做,所有变量在使用前必须显式的声明,否则将会抛出一个 ReferenceError 错误。

"use strict";
v = 1;        // 此处报错:Uncaught ReferenceError: v is not defined
for(i = 0; i < 2; i++) { // 此处报错:Uncaught ReferenceError: i is not defined
}

2、不允许删除变量或函数
在严格模式下,如果您尝试删除一个变量或函数,则会抛出语法错误。而在普通模式下,虽然不会成功,但并不报错。

"use strict";
var person = {name: "Peter", age: 28};
delete person;  // 此处报错:Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
function sum(a, b) {
    return a + b;
}
delete sum;  // 此处报错:Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.

3、函数中不允许有同名的参数
在严格模式下,如果函数中有两个或多个同名参数,则会抛出语法错误,而在普通模式下则不会。

"use strict";
function square(a, a) {     // 此处报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context
    return a * a;
}

4、eval 语句的作用域是独立的
普通模式下,eval 语句的作用域取决于它所在的位置,而在严格模式下,eval 语句本身就是一个局部作用域,通过 eval 语句生成的变量只能在 eval 语句内使用。

"use strict";
eval("var x = 5; console.log(x);");
console.log(x);     // 此处报错:Uncaught ReferenceError: x is not defined

5、不允许使用 with 语句
在严格模式下,不允许使用 with 语句。

"use strict";
var radius1 = 5;
var area1 = Math.PI * radius1 * radius1;
var radius2 = 5;
with(Math) {        // 此处报错:Uncaught SyntaxError: Strict mode code may not include a with statement
    var area2 = PI * radius2 * radius2;
}

6、不允许写入只读属性
在严格模式下,不允许为只读或不存在的属性赋值,否则会造成语法错误,而在普通模式下,虽然不会成功,但并不会报错。

"use strict";
var person = {name: "Peter", age: 28};
Object.defineProperty(person, "gender", {value: "male", writable: false});
person.gender = "female"; // 此处报错:Uncaught TypeError: Cannot assign to read only property 'gender' of object '#<Object>'

7、不允许使用八进制数
在严格模式下,不允许使用八进制数(以零为前缀的数字,例如 010、0377),而在普通模式下则可以。

"use strict";
var x = 010; // 此处报错:Uncaught SyntaxError: Octal literals are not allowed in strict mode.
console.log(parseInt(x));

8、不能在 if 语句中声明函数
在严格模式下,不能在 if 语句中声明函数,调用在 if 语句中定义的函数时,会提示函数未定义。

"use strict";
//如果在if语句中声明函数,则会产生语法错误
if (true) {
    function demo() { // 此处报错:Uncaught ReferenceError: demo is not defined
        console.log("https://www.csdn.net/");
    }
}
demo();

9、禁止使用 this 表示全局对象
在普通模式下,this 关键字表示全局对象 window,而在严格模式下,this关键字则表示 undefined。

"use strict";
var name = "https://www.csdn.net/";
function demoTest() {
    console.log(this); 
}
demoTest();

JS 解析JSON

JSON 全称为“JavaScript Object Notation”,是当前最流行的一种轻量级的数据交换格式,用来存储和传输数据,通常服务器端与客户端在进行交互时就是使用 JSON 格式的数据。

1. 什么是 JSON

JSON 是从 JavaScript 脚本中演变而来的,并且使用 JavaScript 中的语法来描述数据。与 XML 一样,JSON 也是一种基于文本的格式,文件扩展名为 .json

目前大多数编程语言(例如 PHP、Java、.Net)都支持 JSON,JSON 中有两种基本的结构:

  • 对象:由若干键/值对(即 key:value)组成的无序集合,每个对象以左花括号 { 开始,以右花括号 } 结尾,多个键/值对之间使用逗号 , 分隔;
  • 数组:一个有序的值列表,每个数组以左方括号 [ 开始,以右方括号 ] 结尾,多个值之间使用逗号 , 分隔。

在 JSON 中,属性名称或键都是字符串格式的(需要使用英文的双引号括起来),而值则可以是任意类型,如下所示:

{
    "course": {
        "name": "JavaScript",
        "author": "https://www.csdn.net/",
        "year": 2021,
        "genre": "Getting Started tutorial",
        "bestseller": true
    },
    "fruits": [
        "Apple",
        "Banana",
        "Strawberry",
        "Mango"
    ]
}

2. 在 JavaScript 中解析 JSON 数据

在 JavaScript 中,您可以使用 JSON.parse() 方法来解析 JSON 数据,示例代码如下:

var json = '{"course": {"name": "JavaScript","author": "http://c.biancheng.net/","year": 2021,"genre": "Getting Started tutorial","bestseller": true},"fruits": ["Apple","Banana","Strawberry","Mango"]}';
var obj = JSON.parse(json);
console.log(obj.course);
console.log(obj.fruits);

允许结果如下图所示:
在这里插入图片描述

3. 解析嵌套的 JSON 数据

JSON 数据中的对象和数组可以相互嵌套,一个 JSON 对象中可以包含任意类型的数据(例如数组、嵌套数组、其它 JSON 对象等)。对于相互嵌套的 JSON 数据我们要如何获取呢?示例代码如下:

var json = `{
    "book": {
        "name": "Harry Potter and the Goblet of Fire",
        "author": "J. K. Rowling",
        "year": 2000,
        "characters": ["Harry Potter", "Hermione Granger", "Ron Weasley"],
        "genre": "Fantasy Fiction",
        "price": {
            "paperback": "$10.40", "hardcover": "$20.32", "kindle": "$4.11"
        }
    }
}`;
// 将 JSON 数据转换为 JSON 对象
var obj = JSON.parse(json);
// 打印嵌套的 JSON 数据
function printValues(obj) {
    for (var k in obj) {
        if (obj[k] instanceof Object) {
            printValues(obj[k]);
        } else {
            document.write(obj[k] + "<br>");
        };
    }
};
// 调用 printValues() 函数
printValues(obj);
document.write("<hr>");
// 打印 JSON 数据中的单个值
document.write(obj["book"]["author"] + "<br>");         // 输出: J. K. Rowling
document.write(obj["book"]["characters"][0] + "<br>");  // 输出: Harry Potter
document.write(obj["book"]["price"]["hardcover"]);      // 输出: $20.32

运行结果如下图所示:
在这里插入图片描述

4. 将数据转换为 JSON

在开发过程中,有时我们需要将数据转换为 JSON 格式,方便客户端与服务器端进行数据交互。JavaScript 中提供了 JSON.stringify() 方法来将 JavaScript 值转换为 JSON 格式,如下例所示:

var obj = {
    "name": "JavaScript",
    "author": "https://www.csdn.net/",
    "year": 2021,
    "genre": "Getting Started tutorial",
    "bestseller": true
};
var json = JSON.stringify(obj);
document.write(json);

运行结果如下:

{"name":"JavaScript","author":"https://www.csdn.net/      /","year":2021,"genre":"Getting Started tutorial","bestseller":true}

注意:虽然 JavaScript 对象与 JSON 对象看起来非常相似,但它们并不相同,例如在 JavaScript 中,对象的属性名称可以用单引号 ‘’ 或双引号 “” 括起来,也可以完全省略引号。但是,在 JSON 中,所有属性名称都必须用双引号括起来。

JS cookie的设置、获取和删除

在编程领域,Cookie 代表一种小型的文本文件,可以让开发人员在用户计算机上存储少量的数据(大约 4kb),来记录用户的某些信息,例如用户身份、喜好等,当用户下次访问网站时,网站可以通过检索这些信息来为用户展示个性化页面。另外,一些电商网站的购物车也用到了 Cookie 技术。

在 HTTPS 协议还未诞生之前,Web 浏览器和服务器之间需要通过 HTTP 协议进行通信,HTTP 协议是一种无状态协议,当服务器与浏览器之间完成一次交互(浏览器向服务器发送请求,服务器做出响应)后,链接会被关闭,服务器就会忘记浏览器的一切。Cookie 就是为了让服务器能够记住浏览器而发明的。

当使用浏览器访问某个页面时,可以将一些浏览器的信息会存储在 Cookie 中,浏览器每次向服务器发送请求时,Cookie 会作为请求的一部分一同发送给服务器,这样服务器就能通过 Cookie 中的信息来记住浏览器了。

提示:Cookie 由若干个键/值对组成(例如 key1=value1;key2=value2),一个 Cookie 最大可以存储 4kb 的数据,超过长度的 Cookie 将被忽略。您也可以在浏览器端禁用 Cookie,这样一些借助 Cookie 才能完成的操作将无法进行。另外,不要在 Cookie 中存储账号、密码等敏感信息。

Cookie 最初是为 PHP、ASP 等服务器端脚本语言设计的,但是我们也可以使用 JavaScript 来操作,只是操作起来比较复杂,下面就来简单介绍一下如何使用 JavaScript 来操作 Cookie。

1. JS 设置 Cookie

在 JavaScript 中,您可以通过 document.cookie 属性来创建、读取、修改和删除 Cookie 信息。

创建(设置)新的 Cookie 信息,需要以 name=value 形式的字符串来定义新的 Cookie 信息,如下例所示:

document.cookie = "url=http://c.biancheng.net/";

Cookie 数据中不能包含分号、逗号或空格,因此在将数据存储到 Cookie 之前,可以使用 JavaScript 内置的 encodeURIComponent() 函数对数据进行编码。在读取 Cookie 时,使用对应的 decodeURIComponent() 函数来解析 Cookie 数据,如下例所示:

document.cookie = "url=" + encodeURIComponent("http://c.biancheng.net/");

注意:运行上面的代码,您会发现 Cookie 并没有创建,这是因为 Cookie 是用来与服务器进行交互的,所以要成功创建 Cookie 需要借助服务器环境。您可以阅读《PHP开发环境》一节,来搭建一个简单的开发环境,并将我们定义的 HTML 文件移动到应用目录(默认为安装目录的 apache2/htdocs 目录下)中,然后访问我们的 HTML 文件。

Cookie 并不会一直存在,默认情况下,Cookie 的生命周期就是浏览器的会话周期,即用户关闭浏览器后,Cookie 就会失效。 如果想要延长 Cookie 的生命周期,您可以使用 max-age 属性来指定 Cookie 可以存在的时间(单位为秒),默认为 -1,即关闭浏览器后失效。

如果将 max-age 设置为一个负数,则表示该 Cookie 为临时 Cookie,关闭浏览器后就会失效。如果设置为 0,则表示删除该 Cookie。若要将 Cookie 的生命周期设置为 30 天的话,则可以像下面这样:

document.cookie = "url=http://c.biancheng.net/; max-age=" + 30*24*60*60;

此外,您也可以使用 expires 属性来指定 Cookie 失效的具体日期(GMT/UTC 格式),如下所示:

document.cookie = "url=http://c.biancheng.net/; expires=Sun, 31 Dec 2017 12:00:00 UTC;";

提示:通过为 Cookie 设置生命周期,不仅可以延长 Cookie 存在的时间,还可以让 Cookie 提前失效。

默认情况下,Cookie 可用于同一域名下的所有网页,但如果您为 Cookie 设置了 path 属性,那么 Cookie 就只能在该域名指定路径下的网页中使用,例如网站的域名为 c.biancheng.net,若 path 属性设置为 /,则表示 Cookie 可在域名下的所有网页中使用,若 path 属性设置为 /javascript/,则 Cookie 只可在 http://c.biancheng.net/javascript/ 下的网页中使用,示例代码如下:

document.cookie = "url=http://c.biancheng.net/; path=/";

如果您希望 Cookie 可以在指定域名下的子域名中使用,则可以通过 domain 属性来设置,默认情况下,Cookie 仅可在设置它的域名下使用,示例代码如下:

document.cookie = "url=http://c.biancheng.net/; path=/; domain=.biancheng.net";

若将 domain 属性设置为 .biancheng.net,则表示 Cookie 可在所有以 biancheng.net 结尾的域名下使用,注意,domain 属性值的第一个字符 . 不能省略。

此外,Cookie 中还有一个属性 secure,该属性只有一个属性名,没有属性值,如果设置了该属性,则表示 Cookie 将仅通过 HTTPS 协议传输,示例代码如下:

document.cookie = "url=http://c.biancheng.net/; path=/; domain=.biancheng.net; secure";

为了方便设置 Cookie,我们可以定义一个函数,如下所示:

/**
* 添加 Cookie
* @param {[string]} name       [Cookie 的名称]
* @param {[string]} value      [Cookie 的值]
* @param {[number]} daysToLive [Cookie 的过期时间]
*/
function setCookie(name, value, daysToLive) {
    // 对 cookie 值进行编码以转义其中的分号、逗号和空格
    var cookie = name + "=" + encodeURIComponent(value);
   
    if(typeof daysToLive === "number") {
        /* 设置 max-age 属性 */
        cookie += "; max-age=" + (daysToLive*24*60*60);
    }
    document.cookie = cookie;
}

2. JS 获取 Cookie

读取(获取) Cookie 同样使用 document.cookie 即可,该属性会返回一个字符串,字符串中包含除 max-age、expires、path 和 domain 等属性之外的所有 Cookie 信息,例如 url=http://c.biancheng.net/; course=JavaScript。为了获取单个 Cookie 的值,我们可以通过 split() 函数将包含 Cookie 信息的字符串拆分为数组,然后再获取某个 Cookie 的值,示例代码如下:

document.cookie = "url=http://c.biancheng.net/; max-age=" + 30*24*60*60;
document.cookie = "course=JavaScript";
document.cookie = "title=cookie";       
function getCookie(name) {
    // 拆分 cookie 字符串
    var cookieArr = document.cookie.split(";");
   
    // 循环遍历数组元素
    for(var i = 0; i < cookieArr.length; i++) {
        var cookiePair = cookieArr[i].split("=");
       
        /* 删除 cookie 名称开头的空白并将其与给定字符串进行比较 */
        if(name == cookiePair[0].trim()) {
            // 解码cookie值并返回
            return decodeURIComponent(cookiePair[1]);
        }
    }
    // 如果未找到,则返回null
    return null;
}
document.write("url = " + getCookie("url") + "<br>");           // 输出:url = http://c.biancheng.net/
document.write("course = " + getCookie("course") + "<br>");     // 输出:course = JavaScript
document.write("title = " + getCookie("title"));                // 输出:title = cookie

3. JS 修改或更新 Cookie 的值

修改或更新 Cookie 值的唯一方法就是创建一个同名的 Cookie,来替换要修改的 Cookie。注意,若要修改的 Cookie 定义了 path 属性,在修改该属性时也要定义相同的 path 属性,否则会创建一个新的 Cookie。示例代码如下:

// 创建一个 Cookie
document.cookie = "url=http://c.biancheng.net/; path=/; max-age=" + 30*24*60*60;
// 修改这个 Cookie
document.cookie = "url=http://c.biancheng.net/javascript/; path=/; max-age=" + 365*24*60*60;

提示:若 path 属性为 /,在修改时也可以省略 path 属性。

4. JS 删除 Cookie

删除 Cookie 与修改 Cookie 类似,只需要重新将 Cookie 的值设置为空,并将 expires 属性设置为一个过去的日期即可,如下例所示:

// 创建一个 Cookie
document.cookie = "url=http://c.biancheng.net/; path=/; max-age=" + 30*24*60*60;
// 删除这个 Cookie
document.cookie = "url=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

另外,也可通过将 max-age 属性设置为 0 来删除 Cookie。

JS Ajax 请求

Ajax 全称“Asynchronous JavaScript and XML”,译为“异步 JavaScript 和 XML”,程序员们习惯称之为“阿贾克斯”,它并不是一种技术,而是多种技术的综合体,其中包括 JavaScript、XML、JSON、DOM、CSS、HTML 以及最重要的 XMLHttpRequest 对象。通过 Ajax 可以异步从服务器请求数据并将数据更新到网页中,整个过程不需要重载(刷新)整个网页,可以将网页的内容更快的呈现给用户。

这里的异步是指,当程序执行到 Ajax 代码时,将 Ajax 代码交给另外一个线程来执行,不论执行结果如何,当前线程会继续向下执行。

提示:虽然 X 在 Ajax 中代表 XML,但是由于 JSON 的诸多优势(比如 JSON 属于 JavaScript 的一部分,而且更加轻量),目前 Ajax 中普遍使用 JSON 来传输数据。

1. Ajax 的工作原理

JavaScript 需要使用浏览器内置的 XMLHttpRequest 对象向服务器发送 HTTP 请求,并接收服务器响应的数据。

提示:目前,所有的浏览器(Chrome、Firefox、IE7 及以上版本、Safari、Opera 等)都支持 XMLHttpRequest 对象。

下图演示了 Ajax 通信的工作原理:
在这里插入图片描述
因为 Ajax 请求是异步执行的,Ajax 请求发送之后,代码会继续向下执行,直至结束。

2. 发送 Ajax 请求

要发送 Ajax 请求,首先需要实例化一个 XMLHttpRequest 对象,示例代码如下:

var request = new XMLHttpRequest();

然后,使用 XMLHttpRequest 对象的 open() 方法来初始化一个请求,open() 方法的语法格式如下:

XMLHttpRequest.open(method, url, async, user, password);

参数说明如下:

  • method:请求的类型(使用的 HTTP 方法),例如 GET、POST、PUT、HEAD、DELETE 等;
  • url:请求的地址;
  • async:可选参数,布尔类型,表示是否请求是否异步执行,默认值为 true;
  • user:可选参数,表示用户名,主要用来认证,默认值为 null;
  • password:可选参数,表示密码,同样用来认证,默认值为 null。

提示:与前面介绍的《Cookie》类似,Ajax 同样需要服务器环境才行。

示例代码如下:

var request = new XMLHttpRequest();
request.open('GET', 'test.php');

提示:请求地址一般为服务器端脚本文件,例如 .php、.asp 格式的文件,它们可以在服务器将响应信息发送给浏览器之前执行某些操作,例如从数据库中查询或写入数据。

最后,使用 XMLHttpRequest 对象的 send() 方法将请求发送到服务器,send() 方法的语法格式如下:

XMLHttpRequest.send(body);

其中 body 是一个可选参数,表示请求主体,即请求中要发送的数据,如果不需要在请求时发送数据,例如发送 GET 请求,就可以忽略该参数或者传入 null。

提示:如果请求方法为 GET 或 HEAD,则应该将请求主体设置为 null 或者忽略请求主体。

示例代码如下:

var request = new XMLHttpRequest();
request.open('GET', './test.php');
request.send(null);

3. 检索响应信息

请求发送成功后(即使用 send() 方法发送请求后),可以通过检索 XMLHttpRequest 对象来获取服务器的响应信息,XMLHttpRequest 对象中有许多与响应有关的属性,例如:

  • XMLHttpRequest.readyState:一个无符号整型数字,表示请求的状态码,取值如下所示:
    • 0:未初始化,尚未调用 open() 方法;
    • 1:启动,已调用 open() 方法,但尚未调用 send() 方法;
    • 2:发送,已调用 send() 方法,但尚未接收到响应;
    • 3:接收,已接收到部分响应数据,但尚未完成;
    • 4:完成,已接收到全部响应数据,可以在客户端使用了。
  • XMLHttpRequest.onreadystatechange:指定一个函数(回调函数),当 readyState 的值发生改变时,就会调用这个函数;
  • XMLHttpRequest.responseText:请求的响应信息,如果请求未成功或尚未发送请求,则为 null;
  • XMLHttpRequest.responseType:一个枚举值,用于指定响应中包含的数据类型;
  • XMLHttpRequest.responseURL:返回响应的序列化 URL(与请求的 URL 相同),如果 URL 为空则返回空字符串;
  • XMLHttpRequest.responseXML:返回一个包含 HTML 或 XML 的 Document 对象,若请求未成功、未发送或响应数据无法解析为 XML 或 HTML 则返回 null;
  • XMLHttpRequest.status:一个无符号整型数字,表示请求的响应状态码,常见的响应状态码如下所示:
    • 200:请求成功,服务器成功处理了请求;
    • 404:请求失败,服务器未找到请求的页面;
    • 500:服务器暂时不可用。
  • XMLHttpRequest.statusText:一个字符串,表示响应状态的文本信息,例如“OK”或“Not Found”;
  • XMLHttpRequest.timeout:一个无符号整型数字,表示请求的超时时间,单位为毫秒,若超过该时间,请求会自动终止,默认值为 0,表示没有超时时间;
  • XMLHttpRequest.upload:返回一个 XMLHttpRequestUpload 对象,用来表示上传的进度。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <div id="result"></div>
    <button type="button" onclick="displayFullName()">点击发送请求</button>
    <script>
        function displayFullName() {
            // 创建 XMLHttpRequest 对象
            var request = new XMLHttpRequest();
            // 实例化请求对象
            request.open("GET", "test.php?name=C语言中文网&url=http://c.biancheng.net/");
            // 监听 readyState 的变化
            request.onreadystatechange = function() {
                // 检查请求是否成功
                if(this.readyState === 4 && this.status === 200) {
                    // 将来自服务器的响应插入当前页面
                    document.getElementById("result").innerHTML = this.responseText;
                }
            };
            // 将请求发送到服务器
            request.send();
        }
    </script>
</body>
</html>

test.php 文件中的代码如下:

<?php
    if(isset($_GET["name"]) && isset($_GET["url"])) {
        $name = htmlspecialchars($_GET["name"]);
        $url = htmlspecialchars($_GET["url"]);
        // 输出欢迎信息
        echo "欢迎访问 $name! 本站网址为:$url";
    } else {
        echo "你好!欢迎访问我们的网站。";
    }
?>

JS 类型转换

JavaScript 中有五种基本数据类型(其中包括 String、Number、Boolean、Function、Symbol)、三种对象类型(其中包括 Object、Date、Array)和两种特殊类型(其中包括 Null、Undefined)。不同的类型之间运算需要先对数据的类型进行转换,类型转换是将一种数据类型转换为另一种数据类型的过程,在日常开发中,我们会经常用到。

在 JavaScript 有两种类型转换的方式,分别是隐式类型转换和强制类型转换(也叫显式类型转换)。

1. JS 隐式类型转换

隐式转换就是自动转换,通常发生在一些数学运算中。因为 JavaScript 是一种弱类型的语言,在一个表达式中,运算符两边的类型可以不同(比如一个字符串和一个数字相加),JavaScript 解释器会在运算之前将它们的类型进行转换,如下所示:

var str = "https://www.csdn.net/";
var num = 123;
var res = str + num;
document.write(typeof res);  // 输出:string
document.write(res);         // 输出:https://www.csdn.net/123

通过运行结果可以看出,将一个字符串与一个数字相加,会得到一个字符串类型的值。如果是在 C语言或者 Java 语言中的话,上面的运算会因为运算符两边的数据类型不一致而导致报错,但在 JavaScript 中则不会,因为在运算之前 JavaScript 解释器会将上面的 num 变量隐式的转换为字符串类型,之后再进行运算。

JavaScript 中,表达式中包含以下运算符时,会发生隐式类型转换:

  • 算术运算符:加(+)、减(-)、乘(*)、除(/)、取模(%);
  • 逻辑运算符:逻辑与(&&)、逻辑或(||)、逻辑非(!);
  • 字符串运算符:+、+=。

示例代码如下:

document.write("3" - 2);           // 输出:1
document.write("3" + 2);           // 输出:"32"
document.write(3 + "2");           // 输出:"32"
document.write("3" * "2");         // 输出:6
document.write("10" / "2");        // 输出:5
document.write(1 + true);          // 输出:2
document.write(1 + false);         // 输出:1
document.write(1 + undefined);     // 输出:NaN
document.write(3 + null);          // 输出:3
document.write("3" + null);        // 输出:"3null"
document.write(true + null);       // 输出:1
document.write(true + undefined);  // 输出:NaN

通过运行结果可以得出:

  • 字符串加数字,数字会转换为字符串;
  • 数字减字符串,字符串会转换为数字,如果字符串无法转换为数字(例如"abc"、“JavaScript”),则会转换为 NaN;
  • 字符串减数字,字符串会转换为数字,如果字符串无法转换为数字,则会转换为 NaN;
  • 乘、除运算时,也会先将字符串转换为数字。

2. JS 强制类型转换

与隐式类型转换相反,强制类型转换需要手动进行,在 JavaScript 中,强制类型转换主要是通过调用全局函数来实现的,例如 Number()、Boolean()、parseInt()、parseFloat() 等。

1) 使用 Number() 函数

Number() 函数的语法格式如下:

Number(value);
示例代码如下:

document.write(Number("10.5"));  // 输出:10.5
document.write(Number(true));    // 输出:1
document.write(Number(false));   // 输出:0
document.write(Number(null));    // 输出:0

在使用 Number() 函数时,有以下几点需要注意:

  • 如果参数中只包含数字,将转换为十进制数字,忽略前导 0 以及前导空格,如果数字前面有负(-)号,那么-会保留在转换结果中,如果数字前面有加(+)号,转换后会删掉+号;
  • 如果参数中包含有效浮点数字,将转换为对应的浮点数字,忽略前导 0 以及前导空格,同样对于数字前的正负号,会保留负号忽略正号;
  • 如果参数中包含有效的十六进制数字,将转换为对应大小的十进制数字;
  • 如果参数为空字符串,将转换为 0;
  • 如果参数为布尔值,则将 true 转换为 1,将 false 转换为 0;
  • 如果参数为 null,将转换为 0;
  • 如果参数为 undefined,将转换为 NaN;
  • 如果参数为 Date 对象,将转换为从 1970 年 1 月 1 日到执行转换时的毫秒数;
  • 如果参数为函数、包含两个元素以上的数组对象以及除 Date 对象以外的其他对象,将转换为 NaN;
  • 如果在参数前面包含了除空格、+-以外的其他特殊符号或非数字字符,或在参数中间包含了包括空格、+-的特殊符号或非数字字符,将转换为 NaN。

2) 使用 parseInt() 函数

parseInt() 函数的语法格式如下:

parseInt(string, radix);

其中 string 为要转换的值,如果参数不是一个字符串,则会先将其转换为字符串,字符串开头的空白将会忽略;radix 为一个可选参数,表示字符串的基数,取值范围在 2 到 36 之间,例如将 radix 参数设置为 16,则表示将 string 转换为一个十六进制数。

在使用 parseInt() 函数时,有以下几点需要注意:

  • 解析字符串时,会忽略字符串前后的空格,如果字符串第一个字符为负号(-),那么负号会保留在转换结果中,如果字符串第一个字符为正号(+),那么转换后将忽略正号;
  • 如果字符串前面为除空格、正号(+)、负号(-)以外的特殊符号或者除 a~f(或 A~F)之外的非数字字符,那么字符串将不会被解析,返回结果为 NaN;
  • 在字符串中包含空格、小数点(.)等特殊符号或非数字的字符时,解析将在遇到这些字符时停止,并返回已解析的结果;
  • 如果字符串是空字符串,返回结果为 NaN。

示例代码如下:

document.write(parseInt("1101",2));   // 输出:13
document.write(parseInt("a37f",16));  // 输出:41855
document.write(parseInt("123"));      // 输出:123
document.write(parseInt("  123"));    // 输出:123

3) 使用 parseFloat() 函数

parseFloat() 函数的语法格式如下:

parseFloat(string);

其中 string 为要被转换为浮点数的值,如果转换失败,则会返回 NaN。

在使用 parseFloat() 函数时,有以下几点需要注意:

  • 如果在解析的过程中遇到了正号(+)、负号(-)、数字(0-9)、小数点(.)、或科学计数法中的指数(e 或 E)以外的字符,则会忽略该字符以及之后的所有字符,并返回解析到的浮点数;
  • 解析过程中若遇到多个小数点,则会在解析到第二个小数点时停止,并返回第二个小数点之前的解析结果;
  • 解析过程中会忽略参数开头或末尾的空白字符;
  • 如果参数的第一个字符不能被解析为数字,则会返回 NaN。

示例代码如下:

document.write(parseFloat("312.456"));  // 输出:312.456
document.write(parseFloat("-3.12"));    // 输出:-3.12
document.write(parseFloat("+3.12"));    // 输出:3.12
document.write(parseFloat(".12"));      // 输出:0.12

JS 事件冒泡与事件捕获

在 JavaScript 中,我们将事件发生的顺序称为“事件流”,当我们触发某个事件时,会发生一些列的连锁反应,例如有如下所示的一段代码:

<body>
    <div id="wrap">
        <p class="hint">
            <a href="#">Click Me</a>
        </p>
    </div>
</body>

如果给每个标签都定义事件,当我们点击其中的

<

a

>

<a>

<a> 标签时,会发现绑定在

<

d

i

v

>

<div>

<div>

<

p

>

<p>

<p> 标签上的事件也被触发了,这到底是为什么呢?为了解答这一问题,微软和网景两公司提出了两种不同的概念,事件捕获与事件冒泡:

  • 事件捕获:由微软公司提出,事件从文档根节点(Document 对象)流向目标节点,途中会经过目标节点的各个父级节点,并在这些节点上触发捕获事件,直至到达事件的目标节点;
  • 事件冒泡:由网景公司提出,与事件捕获相反,事件会从目标节点流向文档根节点,途中会经过目标节点的各个父级节点,并在这些节点上触发捕获事件,直至到达文档的根节点。整个过程就像水中的气泡一样,从水底向上运动。

提示:上面提到的目标节点指的是触发事件的节点。

后来,W3C 为了统一标准,采用了一个折中的方式,即将事件捕获与事件冒泡合并,也就是现在的“先捕获后冒泡”,如下图所示:
在这里插入图片描述

1. 事件捕获

在事件捕获阶段,事件会从 DOM 树的最外层开始,依次经过目标节点的各个父节点,并触发父节点上的事件,直至到达事件的目标节点。以上图中的代码为例,如果单击其中的 标签,则该事件将通过 document -> div -> p -> a的顺序传递到 标签。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div id="wrap">DIV
        <p class="hint">P
            <a href="#">A</a>
        </p>
    </div>
    <script>
        function showTagName() {
            alert("事件捕获: " + this.tagName);
        }
        var elems = document.querySelectorAll("div, p, a");
        for (let elem of elems) {
            elem.addEventListener("click", showTagName, true);
        }
    </script>
</body>
</html>

运行上面的代码,单击最内层的

<

a

>

<a>

<a> 标签,运行结果如下图所示:
在这里插入图片描述

2. 事件冒泡

事件冒泡正好与事件捕获相反,事件冒泡是从目标节点开始,沿父节点依次向上,并触发父节点上的事件,直至文档根节点,就像水底的气泡一样,会一直向上。

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div onclick="alert('事件冒泡: ' + this.tagName)">DIV
        <p onclick="alert('事件冒泡: ' + this.tagName)">P
            <a href="#" onclick="alert('事件冒泡: ' + this.tagName)">A</a>
        </p>
    </div>
</body>
</html>

运行上面的代码,单击最内层的 <a> 标签,运行结果如下图所示:
在这里插入图片描述

3. 阻止事件捕获和冒泡

了解了事件捕获和事件冒泡后会发现,这个特性并不友好,例如我们在某个节点上绑定了事件,本想在点击时触发这个事件,结果由于事件冒泡,这个节点的事件被它的子元素给触发了。我们要如何阻止这样的事情发生呢?

JavaScript 中提供了 stopPropagation() 方法来阻止事件捕获和事件冒泡的发生,语法格式如下:

event.stopPropagation();

注意:stopPropagation() 会阻止事件捕获和事件冒泡,但是无法阻止标签的默认行为,例如点击链接任然可以打开对应网页。
示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div id="wrap">DIV
        <p class="hint">P
            <a href="#">A</a>
        </p>
    </div>
    <script>
        function showAlert(event) {
            alert("您点击了 "+ this.tagName + " 标签");
            event.stopPropagation();
        }
        var elems = document.querySelectorAll("div, p, a");
        for(let elem of elems) {
            elem.addEventListener("click", showAlert);
        }
    </script>
</body>
</html>

此外,您也可以使用 stopImmediatePropagation() 方法来阻止同一节点的同一事件的其它事件处理程序,例如为某个节点定义了多个点击事件,当事件触发时,这些事件会按定义顺序依次执行,如果其中一个事件处理程序中使用了 stopImmediatePropagation() 方法,那么剩下的事件处理程序将不再执行。

stopImmediatePropagation() 方法的语法格式如下:

event.stopImmediatePropagation();

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
    <style type="text/css">
        div, p, a {
            padding: 15px 30px;
            display: block;
            border: 2px solid #000;
            background: #fff;
        }
    </style>
</head>
<body>
    <div onclick="alert('您点击了 ' + this.tagName + ' 标签')">DIV
        <p onclick="alert('您点击了 ' + this.tagName + ' 标签')">P
            <a href="#" id="link">A</a>
        </p>
    </div>
    <script>
        function sayHi() {
            alert("事件处理程序 1");
            event.stopImmediatePropagation();
        }
        function sayHello() {
            alert("事件处理程序 2");
        }
        // 为 id 为 link 的标签定义多个点击事件
        var link = document.getElementById("link");
        link.addEventListener("click", sayHi); 
        link.addEventListener("click", sayHello);
    </script>
</body>
</html>

4. 阻止默认操作

某些事件具有与之关联的默认操作,例如当您单击某个链接时,会自动跳转到指定的页面,当您单击提交按钮时,会将数据提交到服务器等。如果不想这样的默认操作发生,可以使用 preventDefault() 方法来阻止,其语法格式如下:

event.preventDefault();

示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <a href="http://c.biancheng.net/" id="link">链接</a>
    <script>
        var link = document.getElementById("link");
        link.addEventListener('click', function(event){
            event.preventDefault(); // 阻止链接跳转
        });
    </script>
</body>
</html>

注意:IE9 及以下的版本不支持 preventDefault() 方法,对于 IE9 及以下的浏览器您可以使用 event.returnValue = false;

JS事件委托(事件代理)

利用 JS 事件冒泡动态为元素绑定事件的方法称为事件委托(Event Delegation,也称为“事件代理”),是 JavaScript 中最热门的技术之一。

事件委托就是把原本需要绑定在子元素上的事件(onclick、onkeydown 等)委托给它的父元素,让父元素来监听子元素的冒泡事件,并在子元素发生事件冒泡时找到这个子元素。

举个简单的例子,整个宿舍的同学都需要去取快递,一种方法是让他们一个个去取,另一种方法是把这件事委托给宿舍长,让宿舍长把所有人的快递都取回来,然后再根据收件人一一分发给宿舍的同学。在这里,我们可以将取快递看作一个事件;每个同学看作是需要绑定事件的 DOM 元素;宿舍长看作是这些 DOM 元素的父元素,事件需要绑定在这个父元素上;按照收件人分发快递的过程就是事件执行的过程。

1. 为什么要使用事件委托

在 JavaScript 中,页面内事件处理程序的个数会直接影响页面的整体性能,因为每个事件处理程序都是对象,对象会占用内存,内存中的对象越多,页面的性能则越差。此外,事件处理程序需要与 DOM 节点进行交互,访问 DOM 的次数越多,引起浏览器重绘和重排的次数也就越多,从而影响页面的性能。

重绘是指当元素样式改变时,浏览器会根据元素的新样式重新绘制元素的外观。重排是指当 DOM 树的一部分发生变化时(例如元素尺寸改变),浏览器会重新创建 DOM 树。

当页面中很多表格或列表需要添加事件时,如果逐个添加那就太麻烦了,但是使用事件委托就能极大的减轻我们的工作量,同时也能提高页面的性能。

2. 事件委托实现原理

事件委托是利用事件的冒泡原理来实现的,大致可以分为三个步骤:

  • 确定要添加事件元素的父级元素;
  • 给父元素定义事件,监听子元素的冒泡事件;
  • 使用 event.target 来定位触发事件冒泡的子元素。

注意:使用事件委托时,并不是说把事件委托给随意一个父元素就行。因为事件冒泡的过程也需要消耗时间,距离越远,所需的时间也就越长,所有最好在直接父元素上使用事件委托。

假如我们要为 ul 列表下的每个 li 标签添加点击事件,如果不使用事件委托,最简单的办法就是使用循环来为每个 li 标签绑定事件,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <ul id="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        window.onload = function(){
            var the_ul = document.getElementById('list');
            var the_li = the_ul.getElementsByTagName('li');
            for( var i=0; i < the_li.length; i++ ){
                the_li[i].onclick = function(){
                    console.log(this.innerHTML)
                }
            }
        }
    </script>
</body>
</html>

通过上面的代码可以看出,要为每个 li 标签绑定点击事件,首先需要找到 ul 标签,然后通过 ul 标签找到所有 li 标签, 最后在通过遍历所有 li 标签来绑定事件。若使用事件委托的话,就会简单很多,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <ul id="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        window.onload = function(){
            var the_ul = document.getElementById('list');
            the_ul.onclick = function(e){
                console.log(e.target.innerHTML)
            }
        }
    </script>
</body>
</html>

通过代码可以看出,使用事件委托我们只需要为 ul 标签绑定事件,当 li 标签被点击时,由于事件冒泡的特性,会触发 ul 标签上的事件,我们只需要在事件中通过 event 对象中的 target 属性来找到被点击的 li 标签即可。不过这样做也有一个弊端,那就是当我们点击 ul 标签时,也会触发事件。

另外,如果我们需要动态的向 ul 标签中添加 li 标签,同时也需要在新添加的 li 标签中添加点击事件,就必须通过事件委托来实现了,示例代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript</title>
</head>
<body>
    <ul id="list" style="width: 100px;margin:0;float: left;">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <button style="float:left;" id="addli">添加一个 li</button>
    <button style="float:left;" id="delli">删除一个 li</button>
    <script>
        window.onload = function(){
            var the_ul = document.getElementById('list');
            var the_li = the_ul.getElementsByTagName('li');
            var sum = the_li.length
            the_ul.onclick = function(e){
                console.log(e.target.innerHTML)
            };
            document.getElementById('addli').onclick = function (){
                var newli = document.createElement("li");
                newli.innerHTML = ++sum;
                the_ul.appendChild(newli);
            };
            document.getElementById('delli').onclick = function (){
                the_ul.firstElementChild.remove();
            };
        }
    </script>
</body>
</html>

3. 事件委托的优点

1) 减小内存消耗

使用事件委托可以大量节省内存,减少事件的定义,通过上面的示例可以看出,要为 ul 标签下的所有 li 标签添加点击事件,如果分别为每个 li 标签绑定事件,不仅写起来比较繁琐,而且对内存的消耗也非常大。而使用事件委托的方式将点击事件绑定到 ul 标签上,就可以实现监听所有 li 标签,简洁、高效。

2) 动态绑定事件

在网页中,有时我们需要动态增加或移除页面中的元素,比如上面示例中动态的在 ul 标签中添加 li 标签,如果不使用事件委托,则需要手动为新增的元素绑定事件,同时为删除的元素解绑事件。而使用事件委托就没有这么麻烦了,无论是增加还是减少 ul 标签中的 li 标签,即不需要再为新增的元素绑定事件,也不需要为删除的元素解绑事件。

所以使用事件委托动态绑定事件可以减少很多重复工作的。

4. 总结

要使用事件委托,需要保证事件能够发生冒泡,适合使用事件委托的事件有 click、mousedown、mouseup、keydown、keyup、keypress 等。需要注意的是,虽然 mouseover 和 mouseout 事件也会发生事件冒泡,但处理起来非常麻烦,所以不推荐在 mouseover 和 mouseout 事件中使用事件委托。

另外,对于不会发生事件冒泡的事件(例如 load、unload、abort、focus、blur 等),则无法使用事件委托。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注