JavaScript基础知识学习笔记[Web开发]


JavaScript基础知识

本文为学习笔记,参考Javascript.info,菜鸟等文章编写。

跳转连接

  1. JavaScript基础知识学习笔记[Web开发]
  2. JavaScript对象学习笔记[Web开发]
  3. JavaScript数据类型学习笔记[Web开发]
  4. JavaScript函数学习笔记[Web开发]

JavaScript 简介

本体概述

JavaScript 是一门 跨平台面向对象脚本语言,最初被创建的目的是“使网页更生动”。

JavaScript 的 作用

  • 使网页可交互(例如拥有复杂的动画,可点击的按钮,通俗的菜单等)
  • 在服务端执行,例如 Node.js,可以在网页上添加更多功能,不仅仅是下载文件(例如在多台电脑之间的协同合作)
  • 可以在任意搭载了 JavaScript 引擎 的设备中执行。
  • 这意味着,在浏览器中,JavaScript 可以改变网页(DOM)的外观与样式。同样地,在服务器上,Node.js 中的 JavaScript 可以对浏览器上编写的代码发出的客户端请求做出响应。

JavaScript 引擎 / JavaScript 虚拟机

  • V8 —— Chrome、Opera 和 Edge 中的 JavaScript 引擎。
  • SpiderMonkey —— Firefox 中的 JavaScript 引擎。
  • ……还有其他一些代号,像 “Chakra” 用于 IE,“JavaScriptCore”、“Nitro” 和 “SquirrelFish” 用于 Safari,等等。

现代的 JavaScript 是一种“安全的”编程语言

它不提供对内存或 CPU 的底层访问,因为它最初是为浏览器创建的,不需要这些功能。

为了用户的(信息)安全,在浏览器中的 JavaScript 的能力是受限的。目的是防止恶意网页获取用户私人信息或损害用户数据。

  • 网页中的 JavaScript 不能读、写、复制和执行硬盘上的任意文件。它没有直接访问操作系统的功能。

    现代浏览器允许 JavaScript 做一些文件相关的操作,但是这个操作是受到限制的。仅当用户做出特定的行为,JavaScript 才能操作这个文件。例如,用户把文件“拖放”到浏览器中,或者通过 <input> 标签选择了文件。

    有很多与相机/麦克风和其它设备进行交互的方式,但是这些都需要获得用户的明确许可。

  • 不同的标签页/窗口之间通常互不了解。有时候,也会有一些联系,例如一个标签页通过 JavaScript 打开的另外一个标签页。但即使在这种情况下,如果两个标签页打开的不是同一个网站(域名、协议或者端口任一不相同的网站),它们都不能相互通信。

    这就是所谓的“同源策略”。为了解决“同源策略”问题,两个标签页必须 包含一些处理这个问题的特定的 JavaScript 代码,并均允许数据交换。

  • JavaScript 可以轻松地通过互联网与当前页面所在的服务器进行通信。但是从其他网站/域的服务器中接收数据的能力被削弱了。尽管可以,但是需要来自远程服务器的明确协议(在 HTTP header 中)。这也是为了用户的信息安全。

浏览器中 JavaScript 的功能

  • 在网页中添加新的 HTML,修改网页已有内容和网页的样式。
  • 响应用户的行为,响应鼠标的点击,指针的移动,按键的按动。
  • 向远程服务器发送网络请求,下载和上传文件。
  • 获取或设置 cookie,向访问者提出问题或发送消息。
  • 记住客户端的数据(“本地存储”)。

手册与规范

JavaScript 的标准化组织是 ECMA——这个欧洲信息与通信系统标准化协会提供基于 Javascript 的标准化方案(ECMA 原先是欧洲计算机制造商协会的首字母缩写)。这种标准化版本的 JavaScript 被称作 ECMAScript,在所有支持该标准的应用中以相同的方式工作。公司可以使用开放标准语言来开发他们自己的 JavaScript 实现版本。ECMAScript 标准在 ECMA-262 规范中进行文档化。

ECMA-262 规范 包含了大部分深入的、详细的、规范化的关于 JavaScript 的信息。这份规范明确地定义了这门语言。

但正因其规范化,对于新手来说难以理解。所以,如果你需要关于这门语言细节最权威的信息来源,这份规范就很适合你(去阅读)。但它并不适合日常使用。

每年都会发布一个新版本的规范。最新的规范草案请见 https://tc39.es/ecma262/。

想了解最新最前沿的功能,包括“即将纳入规范的”(所谓的 “stage 3”),请看这里的提案 https://github.com/tc39/proposals。

MDN(Mozilla)JavaScript 索引 是一个带有用例和其他信息的主要的手册。它是一个获取关于个别语言函数、方法等深入信息的很好的信息来源。JavaScript 参考 - JavaScript | MDN (mozilla.org)

开发者控制台

为了发现错误并获得一些与脚本相关且有用的信息,浏览器内置了“开发者工具”。

通常,开发者倾向于使用 Chrome 或 Firefox 进行开发,因为它们有最好的开发者工具。一些其它的浏览器也提供开发者工具,有时还具有一些特殊的功能,通常它们都是在“追赶” Chrome 或 Firefox。

在浏览器中按下 F12 键打开开发者工具(如果使用 Mac,按Cmd+Opt+J)

在错误信息的下方,有个 > 标志。它代表“命令行”,在“命令行”中,我们可以输入 JavaScript 命令,按下 Enter 来执行。

JavaScript 基础知识

"script” 标签

我们几乎可以使用 <script> 标签将 JavaScript 程序插入到 HTML 文档的任何位置,当浏览器遇到 <script> 标签,代码会自动运行。

外部脚本

如果你有大量的 JavaScript 代码,我们可以将它放入一个单独的文件。

脚本文件可以通过 src 特性(attribute)添加到 HTML 文件中。

<script src="/path/to/script.js"></script>

这里,/path/to/script.js 是脚本文件从网站根目录开始的绝对路径。当然也可以提供当前页面的相对路径。例如,src ="script.js",就像 src="./script.js",表示当前文件夹中的 "script.js" 文件。

也可以提供一个完整的 URL 地址

一般来说,只有最简单的脚本才嵌入到 HTML 中。更复杂的脚本存放在单独的文件中。

使用独立文件的好处是浏览器会下载它,然后将它保存到浏览器的 缓存 中。

之后,其他页面想要相同的脚本就会从缓存中获取,而不是下载它。所以文件实际上只会下载一次。

这可以节省流量,并使得页面(加载)更快。

如果设置了 src 特性,script 标签内容将会被忽略。一个单独的 <script> 标签不能同时有 src 特性和内部包裹的代码。必须进行选择,要么使用外部的 <script src="…">,要么使用正常包裹代码的 <script>

代码结构

语句

语句是执行行为(action)的语法结构和命令。

分号

我们可以在代码中编写任意数量的语句。语句之间可以使用分号进行分割。

当存在换行符(line break)时,在大多数情况下可以省略分号。JavaScript 将换行符理解成“隐式”的分号。这也被称为 自动分号插入

存在 JavaScript 无法确定是否真的需要自动插入分号的情况,这种情况下发生的错误是很难被找到和解决。

即使语句被换行符分隔了,我们依然建议在它们之间加分号。这个规则被社区广泛采用。大部分时候可以省略分号,但是最好不要省略分号。

注释

单行注释以两个正斜杠字符 // 开始。

多行注释以一个正斜杠和星号开始 /* 并以一个星号和正斜杠结束 */

现代模式,“use strict”

长久以来,JavaScript 不断向前发展且并未带来任何兼容性问题。新的特性被加入,旧的功能也没有改变。

这么做有利于兼容旧代码,但缺点是 JavaScript 创造者的任何错误或不完善的决定也将永远被保留在 JavaScript 语言中。

这种情况一直持续到 2009 年 ECMAScript 5 (ES5) 的出现。ES5 规范增加了新的语言特性并且修改了一些已经存在的特性。为了保证旧的功能能够使用,大部分的修改是默认不生效的。你需要一个特殊的指令 —— "use strict" 来明确地激活这些特性。

"use strict" 或者 'use strict'处于脚本文件的顶部时,则整个脚本文件都将以“现代”模式进行工作。

"use strict";

// 代码以现代模式工作
...

请确保 "use strict" 出现在脚本的最顶部,否则严格模式可能无法启用。

没有类似于 "no use strict" 这样的指令可以使程序返回默认模式。

进入了严格模式之后没有办法取消。

当你使用 开发者控制台 运行代码时,请注意它默认是不启动 use strict 的。

有时,当 use strict 会对代码产生一些影响时,你会得到错误的结果。

在控制台中启用 use strict

首先,你可以尝试搭配使用 Shift+Enter 按键去输入多行代码,然后将 use strict 放在代码最顶部,就像这样:

'use strict'; <Shift+Enter 换行>
//  ...你的代码
<按下 Enter 以运行>

在大部分浏览器中都有效,像 Firefox 和 Chrome。

如果依然不行,例如你使用的是旧版本的浏览器,那么有一种很丑但可靠的启用 use strict 的方法。将你的代码放在这样的包装器中:

(function() {
'use strict';

// ...你的代码...
})()

现代 JavaScript 支持 “class” 和 “module” —— 高级语言结构(本教程后续章节会讲到),它们会自动启用 use strict。因此,如果我们使用它们,则无需添加 "use strict" 指令。

当代码全都写在了 class 和 module 中时,则可以将 "use strict"; 这行代码省略掉。

变量

变量 是数据的“命名存储”。

变量声明

在 JavaScript 中创建一个变量,我们需要用到 let 关键字。

let message; // 定义变量
let message = 'Hello!'; // 定义变量,并且赋值
let user = 'John', age = 25, message = 'Hello';

当值改变的时候,之前的数据就被从变量中删除了

一个变量应该只被声明一次。对同一个变量进行重复声明会触发 error。

变量命名

JavaScript 的变量命名有两个限制:

  1. 变量名称必须仅包含字母、数字、符号 $_
  2. 首字符必须非数字。

如果命名包括多个单词,通常采用驼峰式命名法(camelCase)。也就是,单词一个接一个,除了第一个单词,其他的每个单词都以大写字母开头:myVeryLongName

保留字

保留字列表 这张表中的保留字无法用作变量命名,因为它们被用于编程语言本身。

常量

声明一个常数(不变)变量,可以使用 const 而非 let

const day = '18.04.1982';

在较老的脚本中,存在另一个关键字 var

var 声明与 let 相似。大部分情况下,我们可以用 let 代替 var 或者 var 代替 let,都能达到预期的效果

“var” 没有块级作用域

var 声明的变量在代码块外也是可见的

if (true) {
	var test1 = true; // 使用 "var" 而不是 "let"
	let test2 = true; // 使用 "let"
}
alert(test1); // true,变量在 if 结束后仍存在
alert(test2); // ReferenceError: test is not defined 变量在 if 结束后不存在

“var” 允许重新声明

使用 var,我们可以重复声明一个变量,不管多少次都行。如果我们对一个已经声明的变量使用 var,这条新的声明语句会被忽略

“var” 声明的变量,可以在其声明语句前被使用

当函数开始的时候,就会处理 var 声明(脚本启动对应全局变量)。

换言之,var 声明的变量会在函数开头被定义,与它在代码中定义的位置无关(这里不考虑定义在嵌套函数中的情况)。

数据类型

JavaScript 中的值都具有特定的类型。

在 JavaScript 中有 8 种基本的数据类型(译注:7 种原始类型和 1 种引用类型)。

我们可以将任何类型的值存入变量。(例如,一个变量可以在前一刻是个字符串,下一刻就存储一个数字)

Number 类型

数字可以有很多操作,比如,乘法 *、除法 /、加法 +、减法 - 等等。

除了常规的数字,还包括所谓的“特殊数值(“special numeric values”)”也属于这种类型:Infinity-InfinityNaN

Infinity 代表数学概念中的 无穷大 ∞。是一个比任何数字都大的特殊值。我们可以通过除以 0 来得到

NaN 代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果,比如运算中包含字符串。NaN是粘性的。任何对 NaN的进一步数学运算都会返回 NaN。

数学运算是安全的

在 JavaScript 中做数学运算是安全的。我们可以做任何事:除以 0,将非数字字符串视为数字,等等。

脚本永远不会因为一个致命的错误(“死亡”)而停止。最坏的情况下,我们会得到 NaN 的结果。

BigInt 类型

在 JavaScript 中,“number” 类型无法安全地表示大于 (253-1)(即 9007199254740991),或小于 -(253-1) 的整数。

可以通过将 n 附加到整数字段的末尾来创建 BigInt 值。

// 尾部的 "n" 表示这是一个 BigInt 类型
const bigInt = 1234567890123456789012345678901234567890n;

BigInt 类型 是最近被添加到 JavaScript 语言中的,可能在较旧的浏览器中存在兼容问题

String 类型

JavaScript 中的字符串必须被括在引号里。

  1. 双引号:"Hello".
  2. 单引号:'Hello'.
  3. 反引号:`Hello`.

双引号单引号都是“简单”引用,在 JavaScript 中两者几乎没有什么差别。

反引号功能扩展 引号。它们允许我们通过将变量和表达式包装在 ${…} 中,来将它们嵌入到字符串中。

let name = "John";
// 嵌入一个变量
alert( `Hello, ${name}!` ); // Hello, John!
// 嵌入一个表达式
alert( `the result is ${1 + 2}` ); // the result is 3

Boolean 类型

boolean 类型仅包含两个值:truefalse

null 值

特殊的 null 值不属于上述任何一种类型。

它构成了一个独立的类型,只包含 null

undefined 值

特殊值 undefinednull 一样自成类型。

undefined 的含义是 未被赋值

如果一个变量已被声明,但未被赋值,那么它的值就是 undefined

从技术上讲,可以显式地将 undefined 赋值给变量,但是不建议这样做。

Object 类型和 Symbol 类型

其他所有的数据类型都被称为“原始类型”,因为它们的值只包含一个单独的内容(字符串、数字或者其他)。相反,object 则用于储存数据集合和更复杂的实体。

symbol 类型用于创建对象的唯一标识符。我们在这里提到 symbol 类型是为了完整性,但我们要在学完 object 类型后再学习它。

typeof 运算符

typeof 运算符返回参数的类型。当我们想要分别处理不同类型值的时候,或者想快速进行数据类型检验时,非常有用。

typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
typeof Math // "object"  (1)
typeof null // "object"  (2)
typeof alert // "function"  (3)

额外的说明:

  1. Math 是一个提供数学运算的内建 object
  2. typeof null 的结果为 "object"。这是官方承认的 typeof 的错误,这个问题来自于 JavaScript 语言的早期阶段,并为了兼容性而保留了下来。null 绝对不是一个 objectnull 有自己的类型,它是一个特殊值。typeof 的行为在这里是错误的。
  3. typeof alert 的结果是 "function",因为 alert 在 JavaScript 语言中是一个函数。 JavaScript 语言中没有一个特别的 “function” 类型。函数隶属于 object 类型。但是 typeof 会对函数区分对待,并返回 "function"。这也是来自于 JavaScript 语言早期的问题。从技术上讲,这种行为是不正确的,但在实际编程中却非常方便。

typeof(x) 语法

typeof 是一个操作符,不是一个函数。这里的括号不是 typeof 的一部分。它是数学运算分组的括号。

通常,这样的括号里包含的是一个数学表达式,例如 (2 + 2),但这里它只包含一个参数 (x)。从语法上讲,它们允许在 typeof 运算符和其参数之间不打空格,有些人喜欢这样的风格。

交互

alert

alert会显示一条信息,并等待用户按下 “OK”。

弹出的这个带有信息的小窗口被称为 模态窗。“modal” 意味着用户不能与页面的其他部分(例如点击其他按钮等)进行交互,直到他们处理完窗口。在上面示例这种情况下 —— 直到用户点击“确定”按钮。

prompt

prompt 函数接收两个参数:

result = prompt(title, [default]);

浏览器会显示一个带有文本消息的模态窗口,还有 input 框和确定/取消按钮。

  • title

    显示给用户的文本

  • default

    可选的第二个参数,指定 input 框的初始值。

语法中的方括号 [...]

上述语法中 default 周围的方括号表示该参数是可选的,不是必需的。

访问者可以在提示输入栏中输入一些内容,然后按“确定”键。然后我们在 result 中获取该文本。或者他们可以按取消键或按 Esc 键取消输入,然后我们得到 null 作为 result

prompt 将返回用户在 input 框内输入的文本,如果用户取消了输入,则返回 null

//举例
let age = prompt('How old are you?', 100);
alert(`You are ${age} years old!`); // You are 100 years old!

confirm

语法:

result = confirm(question);

confirm 函数显示一个带有 question 以及确定和取消两个按钮的模态窗口。

点击确定返回 true,点击取消返回 false

//举例
let isBoss = confirm("Are you the boss?");
alert( isBoss ); // 如果“确定”按钮被按下,则显示 true

类型转换

大多数情况下,运算符和函数会自动将赋予它们的值转换为正确的类型。在某些情况下,我们需要将值显式地转换为我们期望的类型。

字符串转换 String(value)

数字型转换 Number(value)
在算术函数和表达式中,会自动进行 number 类型转换。当我们从 string 类型源(如文本表单)中读取一个值,但期望输入一个数字时,通常需要进行显式转换。

转换number 类型规则
undefinedNaN
null0
true 和 false1 and 0
string去掉首尾空白字符(空格、换行符 \n、制表符 \t 等)后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0。否则,将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN

布尔型转换 Boolean(value)

布尔转换规则:

  • 直观上为“空”的值(如 0、空字符串、nullundefinedNaN)将变为 false
  • 其他值变成 true

值的比较

数学运算符

  • 大于 / 小于:a > ba < b
  • 大于等于 / 小于等于:a >= ba <= b
  • 检查两个值的相等:a == b,请注意双等号 == 表示相等性检查,而单等号 a = b 表示赋值。
  • 检查两个值不相等:不相等在数学中的符号是 ,但在 JavaScript 中写成 a != b

比较运算符返回布尔值

  • true —— 表示“yes(是)”,“correct(正确)”或“the truth(真)”。
  • false —— 表示“no(否)”,“wrong(错误)”或“not the truth(非真)”。

比较字符串的大小

JavaScript 会使用“字典(dictionary)”或“词典(lexicographical)”顺序进行判定。换言之,字符串是按字符(母)逐个进行比较的。

  1. 首先比较两个字符串的首位字符大小。
  2. 如果一方字符较大(或较小),则该字符串大于(或小于)另一个字符串。算法结束。
  3. 否则,如果两个字符串的首位字符相等,则继续取出两个字符串各自的后一位字符进行比较。
  4. 重复上述步骤进行比较,直到比较完成某字符串的所有字符为止。
  5. 如果两个字符串的字符同时用完,那么则判定它们相等,否则未结束(还有未比较的字符)的字符串更大。

不同类型间的比较

JavaScript 会首先将其转化为数字(number)再判定大小。

alert( '2' > 1 ); // true,字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true,字符串 '01' 会被转化为数字 1
alert( true == 1 ); // true
alert( false == 0 ); // true

严格相等

因为在比较不同类型的值时,处于相等判断符号 == 两侧的值会先被转化为数字,普通的相等性检查 == 存在问题(例如不能区分出 0false

严格相等运算符 === 在进行比较时不会做任何的类型转换。

同样的,与“不相等”符号 != 类似,“严格不相等”表示为 !==

对 null 和 undefined 进行比较

当使用严格相等 === 比较二者时,它们不相等,因为它们属于不同的类型。

当使用非严格相等 == 比较二者时,JavaScript 存在一个特殊的规则,会判定它们相等。

当使用数学式或其他比较方法 < > <= >= 时:null/undefined 会被转化为数字:null 被转化为 0undefined 被转化为 NaN

// 奇怪的结果
alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

//为什么会出现这种反常结果,这是因为相等性检查 == 和普通比较符 > < >= <= 的代码逻辑是相互独立的。进行值的比较时,null 会被转化为数字,因此它被转化为了 0。这就是为什么 null >= 0 返回值是 true,null > 0 返回值是 false。

//另一方面,undefined 和 null 在相等性检查 == 中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。这就解释了为什么 null == 0 会返回 false。

基础运算符,数学运算

常用术语

  • 运算元 : 运算符应用的对象。
    比如说乘法运算 5 * 2,有两个运算元:左运算元 5 和右运算元 2。有时候人们也称其为“参数”而不是“运算元”。
  • 一元运算符:一个运算符对应的只有一个运算元。
    比如说一元负号运算符(unary negation)-,它的作用是对数字进行正负转换
  • 二元运算符:一个运算符拥有两个运算元。
    减号还存在二元运算符形式。

JavaScript支持以下数学运算运算符优先级 - JavaScript | MDN (mozilla.org)

条件分支:if 和 ‘?’

if(...) 语句计算括号里的条件表达式,如果计算结果是 true,就会执行对应的代码块。

elseif 语句包含的一个可选块。如果判断条件不成立,就会执行它内部的代码。

else if 子句可以实现一个条件的几个变体。

建议每次使用 if 语句都用大括号 {} 来包装代码块,即使只有一条语句。这样可以提高代码可读性。

if(...){
   //....
}
else if(...){
    //....
}
else{
    //....
}

条件运算符 ‘?’可以更简短地达到目的。

使用一系列问号 ? 运算符可以返回一个取决于多个条件的值。

let age = prompt('age?', 18);

let message = (age < 3) ? 'Hi, baby!' :
  (age < 18) ? 'Hello!' :
  (age < 100) ? 'Greetings!' :
  'What an unusual age!';

alert( message );

逻辑运算符

JavaScript 中有四个逻辑运算符:||(或),&&(与),!(非),??(空值合并运算符)

已定义的(defined):一个既不是 null 也不是 undefined 的值。

a ?? b 的结果是:

  • 如果 a 是已定义的,则结果为 a
  • 如果 a 不是已定义的,则结果为 b
result = a ?? b
//类似
result = (a !== null && a !== undefined) ? a : b;

使用场景

let user;
// let user = "John";
alert(user ?? "匿名"); // 匿名(user 未定义)

或运算符 || 可以以与 ?? 运算符相同的方式使用。

let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// 显示第一个真值:
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder

出于安全原因,JavaScript 禁止将 ?? 运算符与 &&|| 运算符一起使用,除非使用括号明确指定了优先级。

循环:while 和 for

while 循环
while (condition) {
  // 代码
  // 所谓的“循环体”
}
do…while
do {
  // 循环体
} while (condition);
for( ; ; ) 循环
for (begin; condition; step) {
  // ……循环体……
}
for…in 循环

遍历一个对象的所有键(key)

for (key in object) {
  // 对此对象属性中的每个键执行的代码
}
let user = {
  name: "John",
  age: 30,
  isAdmin: true
};
for (let key in user) {
  // keys
  alert( key );  // name, age, isAdmin
  // 属性键的值
  alert( user[key] ); // John, 30, true
}

for…of 循环

遍历数组,不能获取当前元素的索引,只是获取元素值

let fruits = ["Apple", "Orange", "Plum"];

// 遍历数组元素
for (let fruit of fruits) {
  alert( fruit );
}
break / continue

通常条件为假时,循环会终止。但我们随时都可以使用 break 指令强制退出。

continue 指令不会停掉整个循环。而是停止当前这一次迭代,并强制启动新一轮循环(如果条件允许的话)。

禁止 break/continue 在 ‘?’ 的右边

请注意非表达式的语法结构不能与三元运算符 ? 一起使用。特别是 break/continue 这样的指令是不允许这样使用的。

标签

标签 是在循环之前带有冒号的标识符

有时候需要一次从多层嵌套的循环中跳出来。可以使用标签完成这个过程。

labelName: for (...) {
	//...
	for(...){
        //...
        break labelName;
    }
}

标签并不允许“跳到”代码的任意位置

break label;  // 跳转至下面的 label 处(无效)

label: for (...)

break 指令必须在代码块内。从技术上讲,任何被标记的代码块都有效。

label: {
// ...
break label; // 有效
// ...
}

“switch” 语句

switch 语句可以替代多个 if 判断。

switch 语句为多分支选择的情况提供了一个更具描述性的方式。

switch(x) {
  case 'value1':  // if (x === 'value1')
    ...
    [break]

  case 'value2':  // if (x === 'value2')
    ...
    [break]

  default:
    ...
    [break]
}

函数

函数是程序的主要“构建模块”。函数使该段代码可以被调用很多次,而不需要写重复的代码。

使用 函数声明 创建函数。

function showMessage() {
  alert( 'Hello everyone!' );
}
showMessage();

function 关键字首先出现,然后是 函数名,然后是括号之间的 参数 列表(用逗号分隔,在上述示例中为空,我们将在接下来的示例中看到),最后是花括号之间的代码(即“函数体”)。

局部变量:在函数中声明的变量只在该函数内部可见。

外部变量:函数对外部变量拥有全部的访问权限。函数也可以修改外部变量。

如果在函数内部声明了同名变量,那么函数会 遮蔽 外部变量。

全局变量:任何函数之外声明的变量,都被称为 全局 变量。全局变量在任意函数中都是可见的(除非被局部变量遮蔽)。

减少全局变量的使用是一种很好的做法。现代的代码有很少甚至没有全局变量。大多数变量存在于它们的函数中。但是有时候,全局变量能够用于存储项目级别的数据。

函数表达式 :允许在任何表达式的中间创建一个新函数。

function sayHi() {
  alert( "Hello" );
}
let sayHi = function() {
  alert( "Hello" );
};
// 上面的两个代码示例的含义是一样的:“创建一个函数并将其放入变量 sayHi 中”。

注意:函数是一个值!

function sayHi() {
alert( "Hello" );
}
alert( sayHi ); // 显示函数代码
// 显示的内容:
//function sayHi() {
//  alert( "Hello" );
//}
function sayHi() {   // (1) 创建
alert( "Hello" );
}

let func = sayHi;    // (2) 复制

func(); // Hello     // (3) 运行复制的值(正常运行)!
sayHi(); // Hello    //     这里也能运行(为什么不行呢)

回调函数

通过例子理解:

写一个包含三个参数的函数 ask(question, yes, no)

  • question

    关于问题的文本

  • yes

    当回答为 “Yes” 时,要运行的脚本

  • no

    当回答为 “No” 时,要运行的脚本

函数需要提出 question(问题),并根据用户的回答,调用 yes()no()

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

function showOk() {
  alert( "You agreed." );
}

function showCancel() {
  alert( "You canceled the execution." );
}

// 用法:函数 showOk 和 showCancel 被作为参数传入到 ask
ask("Do you agree?", showOk, showCancel);

ask 的两个参数值 showOkshowCancel 可以被称为 回调函数 或简称 回调

可以使用函数表达式来编写一个等价的、更简洁的函数:

function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}

ask(
"Do you agree?",
function() { alert("You agreed."); },
function() { alert("You canceled the execution."); }
);

函数表达式 与 函数声明 的区别:

函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。

在函数声明被定义之前,它就可以被调用。

箭头函数

//语法
let func = (arg1, arg2, ..., argN) => {
	expression;
};

//等价于
let func = function(arg1, arg2, ..., argN) {
  return expression;
};
  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值