Hello, world!
script 标签
JavaScript程序可以在 <script>
标签的帮助下插入到 HTML 文档的任何地方。 比如:
js
<!DOCTYPE HTML>
<html>
<body>
<p>script 标签之前 ...</p>
<script>
alert('Hello, world!');
</script>
<p>...script 标签之后</p>
</html>
外部脚本
如果你有大量的 JavaScript 代码,我们可以将它放入一个单独的文件
- 通过src 特性(attribute)添加到 HTML 文件中。eg:
<script src="/path/to/script.js"></script>
/path/to/script .js
是脚本文件从网站根目录开始的绝对路径 - 提供当前页面的相对路径。eg:
src ="script .js"
表示当前文件夹中的"script .js"
文件。 - 提供一个完整的 URL 地址,eg:
<script src="<https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js>"></script>
要附加多个脚本,则使用多个标签:
js
<script src="/js/script1.js"></script>
<script src="/js/script2.js"></script>
一个单独的<script>
标签不能同时有 src 特性和内部包裹的代码, 这将不会工作:
js
<script src="file.js">
alert(1); // 此内容会被忽略,因为设定了 src
</script>
一般来说,只有最简单的脚本才嵌入到 HTML 中。更复杂的脚本存放在单独的文件中。这可以节省流量,并使得页面加载更快
代码结构
语句
语句是执行行为(action)的语法结构和命令
代码语句之间可以使用分号进行分割
例如,我们将 " Hello World" 这条信息一分为二:
js
alert('Hello');
alert('World');
通常,每条语句独占一行,以提高代码的可读性
分号
大部分时候可以省略分号,但是最好不要省略分号
注释
添加注释描述代码做了什么和为什么要这样做
单行注释以两个正斜杠字符 // 开始
js
//这行注释独占一行
alert('Hello');
alert('World'); // 这行注释跟随在语句后面
多行注释以一个正斜杠和星号开始 /*
并以一个星号和正斜杆结束 */
js
/* 两个消息的例子。
这是一个多行注释。
*/
alert('Hello');
alert('World');
快捷方式 :
在大多数的编辑器中,可以使用 Ctrl+/ 进行单行注释,Ctrl+Shift+/ 进行多行注释(选择代码,然后按下组合键)
不支持注释嵌套!
现代模式,"use strict"
"use strict"
当"use strict"
处于脚本文件的顶部时,则整个脚本文件都将以"现代"模式进行工作
"use strict"
可以被放在函数体的开头。这样则可以只在该函数中启用严格模式。但通常人们会在整个脚本中启用严格模式- 只有注释可以出现在
"use strict"
的上面 - use strict 一旦设置无法取消
浏览器控制台
当使用开发者控制台运行代码时,是默认不启动 use strict 的
有时,当 use strict 会对代码产生一些影响时,运行后会得到错误的结果。
在控制台中启用 use strict:
首先,可以尝试搭配使用 Shift+Enter 按键去输入多行代码,然后将 use strict 放在代码最顶部,就像这样:
js
'use strict'; <Shift+Enter 换行>
// ...你的代码
<按下 Enter 以运行>
其在大部分浏览器中都有效,像 Firefox 和 Chrome
如果依然不行,例如你使用的是旧版本的浏览器,那么有一种很丑但可靠的启用 use strict 的方法------将你的代码放在这样的包装器中:
js
(function() {
'use strict';
// ...你的代码...
})()
-
现代 JavaScript 支持 "classes" 和 "modules" ------ 高级语言结构(本教程后续章节会讲到),它们会自动启用 use strict 。因此,如果我们使用它们,则无需添加 "use strict" 指令
-
目前最好还是将 "use strict"; 写在脚本的顶部。稍后,当代码全都写在了 class和 module 中时,则可以将 "use strict"; 这行代码省略掉
变量
JavaScript 应用需要处理信息。eg:
1.一个网上商店 ------ 这里的信息可能包含正在售卖的商品和购物车
2.一个聊天应用 ------ 这里的信息可能包括用户和消息等等
变量就是用来储存 这些信息的 变量是数据的"命名存储"。我们可以使用变量来保存商品、访客和其他信息
变量
在 JavaScript 中声明一个变量,需要用 let
关键字
js
let message;//定义(声明)了一个名称为 "message" 的变量
message = 'Hello!';//通过赋值运算符 "=" 为变量添加一些数据
alert(message); // 显示变量内容Hello!
现在这个字符串已经保存到与该变量相关联的内存区域了,我们可以通过使用该变量名称访问它
简洁地,可以将变量定义和赋值合并成一行
js
let message = 'Hello!'; // 定义变量,并且赋值
alert(message); // 显示变量内容Hello!
在一行中声明多个变量:
js
let user = 'John', age = 25, message = 'Hello';
但并不推荐这样,为了更好的可读性,最好一行只声明一个变量
js
let user = 'John';
let age = 25;
let message = 'Hello';
一些程序员采用下面的形式书写多个变量:
js
let user = 'John',
age = 25,
message = 'Hello';
变量声明
变量的声明可以任意改变,声明值改变后,之前的数据就被从变量中删除了
js
let message;
message = 'Hello!';
message = 'World!'; // 值改变了
alert(message);
还可以声明两个变量,然后将其中一个变量的数据拷贝到另一个变量
js
let hello = 'Hello world!';
let message;
message = hello;// 将字符串 'Hello world' 从变量 hello 拷贝到 message
alert(hello); // Hello world!
alert(message); // Hello world!
// 现在两个变量保存着相同的数据
一个变量只能声明一次,对同一个变量进行重复声明会触发 error
- 存在禁止更改变量值的函数式编程语言。比如 Scala 或 Erlang
如果你试图保存其他值,它会强制创建一个新盒子(声明一个新变量),无法重用之前的变量
变量命名
JavaScript 的变量命名的要求:
- 变量名称必须仅包含字母,数字,符号 $ 和 _
- 首字符必须非数字
- 区分大小写
- 如果命名包括多个单词,通常采用驼峰式命名法。即除了第一个单词,其他的每个单词都以大写字母开头:myVeryLongName
- 保留字不能用作变量命名,如let 、 class 、 return 、 function
常量
声明一个常数(不变)变量,使用 const
声明的变量称为"常量"。它们不能被重新赋值,如果尝试修改就会发生报错
js
const myBirthday = '18.04.1982';
myBirthday = '01.01.2001'; // 错误,不能对常量重新赋值
常量的用法
-
当程序员能确定这个变量永远不会改变的时候,就可以使用 const 来确保这种行为,并且清楚地向别人传递这一事实
-
将常量用作别名,以便记住那些在执行之前就已知的难以记住的值。 使用大写字母和下划线来命名这些常量
例如,让我们以所谓的"web"(十六进制)格式为颜色声明常量:
js
const COLOR_RED = "#F00";
const COLOR_GREEN = "#0F0";
const COLOR_BLUE = "#00F";
const COLOR_ORANGE = "#FF7F00";
// ......当我们需要选择一个颜色
let color = COLOR_ORANGE;
alert(color); // #FF7F00
好处:
- COLOR_ORANGE 比 "#FF7F00" 更容易记忆
- 比起 COLOR_ORANGE 而言, "#FF7F00" 更容易输错
- 阅读代码时, COLOR_ORANGE 比 #FF7F00 更易懂
-
有些常量在执行期间被"计算"出来,但初始赋值之后就不会改变。eg:
const pageLoadTime = /* 网页加载所需的时间 */;
pageLoadTime
的值在页面加载之前是未知的,所以采用常规命名。但是它仍然是个常量,因为赋值之后不会改变。 -
大写命名的常量仅用作"硬编码(hard-coded)"值的别名
正确命名变量
变量名应该有清晰、明显的含义,对其存储的数据进行描述
一些可以遵循的规则:
- 使用易读的命名,比如 userName 或者 shoppingCart
- 变量名要在足够简洁的同时准确描述变量,像 data 和 value 这样的名称等于什么都没说,除非能够非常明显地从上下文知道数据和值所表达的含义
- 脑海中的术语要和团队保持一致。如果网站的访客称为"用户",则我们采用相关的变量命名,比如 currentUser(当前用户) 或者 newUser (新用户),而不要使用 currentVisitor (当前访问者)或者一个newManInTown(城里的新人)
- 声明一个新的变量,而非重新赋值现有的变量
数据类型
JavaScript 中的值都具有特定的类型
可以将任何类型的值存入变量
可以重新赋值
js
let message = "hello";
message = 123456;
Number 类型
number
类型代表整数和浮点数
"number" 类型无法表示大于 (2^53^-1) (即 9007199254740991 ),或小于-(2^53^-1) 的整数
数字可以有很多操作,比如,乘法 * 、除法 / 、加法 + 、减法 - 等等。
除了常规的数字,还包括所谓的"特殊数值"也属于这种类型:
Infinity 、 -Infinity 和 NaN
Infinity
代表数学概念中的 无穷大 ∞。是一个比任何数字都大的特殊值。
我们可以通过除以 0 来得到,它或者在代码中直接使用它:
js
alert( 1 / 0 ); // Infinity
alert( Infinity ); // Infinity
NaN
代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果
NaN 是粘性的。任何对 NaN 的进一步操作都会返回 NaN
eg:
js
alert( "not a number" / 2 ); // NaN,这样的除法是错误的
alert( "not a number" / 2 + 5 ); // NaN
BigInt 类型
BigInt
类型用于表示任意长度的整数
通过将 n 附加到整数字段的末尾来创建 BigInt 值
js
// 尾部的 "n" 表示这是一个 BigInt 类型
const bigInt = 1234567890123456789012345678901234567890n;
String 类型
JavaScript 中的字符串必须被括在引号里
js
let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;
在 JavaScript 中,有三种包含字符串的方式
- 双引号:
"Hello"
- 单引号:
'Hello'
- 反引号: `Hello`
- 双引号和单引号都是"简单"引用,在 JavaScript 中两者几乎没有什么差别
- 反引号是 功能扩展 引号。允许我们通过将变量和表达式包装在
${...}
中,来将它们嵌入到字符串中,eg:
js
let name = "John";
// 嵌入一个变量
alert( `Hello, ${name}!` ); // Hello, John!
// 嵌入一个表达式
alert( `the result is ${1 + 2}` ); // the result is 3
${...}
内的表达式会被计算,计算结果会成为字符串的一部分- 可以在
${...}
内放置任何东西:诸如名为 name 的变量,或者诸如 1 + 2 的算数表达式,或者其他一些更复杂的。
注意这仅仅在反引号内有效,其他引号不允许这种嵌入
js
alert( "the result is ${1 + 2}" );// the result is ${1 + 2}(使用双引号则不会计算 ${...} 中的内容)
-
JavaScript 中没有 character 类型。
-
在一些语言中,单个字符有一个特殊的 "character" 类型,在 C 语言和 Java 语言中被称为"char"
在 JavaScript 中没有这种类型。只有一种 string 类型,一个字符串可以包含零个(为空)、一个或多个字符
Boolean 类型(逻辑类型)
boolean
类型仅包含两个值: true
和 false
这种类型通常用于存储表示 yes 或 no 的值:
true 意味着 "yes,正确", false 意味着 "no,不正确
js
let nameFieldChecked = true; // yes, name field is checked
let ageFieldChecked = false; // no, age field is not checked
布尔值也可作为比较的结果:
js
let isGreater = 4 > 1;
alert( isGreater ); // true(比较的结果是 "yes")
"null" 值
特殊的 null
值不属于上述任何一种类型
它构成了一个独立的类型,只包含 null 值:
JavaScript 中的 null 仅仅是一个代表"无"、"空"或"值未知"的特殊值
js
let age = null;//表示 age 是未知的
"undefined" 值
undefined
的含义是 未被赋值
如果一个变量已被声明,但未被赋值,那么它的值就是 undefined :
js
let age;
alert(age); // 弹出 "undefined"
从技术上讲,可以显式地将 undefined 赋值给变量:
js
let age = 100;// 将值修改为 undefined
age = undefined;
alert(age); // "undefined"
- 但是不建议这样做。通常,使用 null 将一个"空"或者"未知"的值写入变量中,而undefined 则保留作为未进行初始化的事物的默认初始值
object 类型和 symbol 类型
object
类型是一个特殊的类型
其他所有的数据类型都被称为"原始类型",因为它们的值只包含一个单独的内容(字符串、数字或者其他)
相反, object 则用于储存 数据集合 和更 复杂的实体
symbol
类型用于创建对象的唯一标识符。我们在这里提到 symbol 类型是为了完整性,但我们要在学完 object 类型后再学习它
typeof 运算符
typeof 运算符以字符串的形式返回数据类型。用于分别处理不同类型值的时候,或者快速进行数据类型检验
它支持两种语法形式:
- 作为运算符: typeof x
- 函数形式: typeof(x)
两种形式得到的结果是一样的
对 typeof x 的调用会以字符串的形式返回数据类型:
js
typeof(x) == "number"//运算数为数字
typeof(x) == "string"//运算数为字符串
typeof(x) == "boolean"//运算数为布尔值
typeof(x) == "object"//运算数为对象、数组和null
typeof(x) == "function"//运算数为函数
typeof(x) == "undefined"//运算数为未定义
eg:
js
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)
最后三行的额外说明:
- typeof null 的结果是 "object" 。这是官方承认的 typeof 的行为上的错误,这个问题来自于 JavaScript 语言的早期,并为了兼容性而保留了下来。 null 绝对不是一个object 。 null 有自己的类型,它是一个特殊值
- typeof alert 的结果是 "function" ,因为 alert 在 JavaScript 语言中是一个函数。我们会在下一章学习函数,那时我们会了解到,在 JavaScript 语言中没有一个特别的 "function"类型。函数隶属于 object 类型。但是 typeof 会对函数区分对待,并返回"function" 。这也是来自于 JavaScript 语言早期的问题。从技术上讲,这种行为是不正确的,但在实际编程中却非常方便
交互:alert、prompt 和 confirm
alert
alert
会显示一条信息,并等待用户按下 "OK"。 例如: alert("Hello");
弹出的这个带有信息的小窗口被称为 模态窗。"modal" 意味着用户不能与页面的其他部分(例如点击其他按钮等)进行交互,直到他们处理完窗口。在上面示例这种情况下 ------ 直到用户点击"确定"按钮
prompt
prompt
函数接收两个参数:
result = prompt(title, [default]);
浏览器会显示一个带有文本消息的模态窗口,还有 input 框和确定/取消按钮
title
title
显示给用户的文本
default
default
指定 input 框的初始值
- 语法中的方括号 [...]
上述语法中 default 周围的方括号表示该参数是可选的,不是必需的
访问者可以在提示输入栏中输入一些内容,然后按"确定"键。然后我们在 result 中获取该文本。或者他们可以按取消键或按 Esc 键取消输入,然后我们得到 null 作为 result
prompt 将返回用户在 input 框内输入的文本,如果用户取消了输入,则返回 null
举个例子:
js
let age = prompt('How old are you?', 100);
alert(`You are ${age} years old!`); // You are 100 years old!
- IE 浏览器会提供默认值
第二个参数是可选的。但是如果我们不提供的话,Internet Explorer 会把 "undefined" 插入到 prompt
我们可以在 Internet Explorer 中运行下面这行代码来看看效果:
let test = prompt("Test");
所以,为了 prompt 在 IE 中有好的效果,我们建议始终提供第二个参数:
let test = prompt("Test", ''); // <-- 用于 IE 浏览器
confirm
语法:
result = confirm(question);
confirm
函数显示一个带有 question
以及确定和取消两个按钮的模态窗口
点击确定返回 true
,点击取消返回 false
例如:
js
let isBoss = confirm("Are you the boss?");
alert( isBoss ); // 如果"确定"按钮被按下,则显示 true
- 这些方法都是模态的:它们暂停脚本的执行,并且不允许用户与该页面的其余部分进行交互,直到窗口被解除 法共有两个限制:
- 模态窗口的确切位置由浏览器决定。通常在页面中心
- 窗口的确切外观也取决于浏览器。我们不能修改它
这就是简单的代价。还有其他一些方法可以显示更漂亮的窗口,并与用户进行更丰富的交互
类型转换
大多数情况下,运算符和函数会自动将赋予它们的值转换为正确的类型
比如, alert 会自动将任何值都转换为字符串以进行显示。算术运算符会将值转换为数字
在某些情况下,则需要将值显式地转换为期望的类型
- 在本章中,不会讨论 object 类型。目前,将只学习原始类型
之后,在学习完 object 类型后,将在 对象 --- 原始值转换 一章中学习对象 --- 原始值转换
字符串转换 string
当需要一个字符串形式的值时,就会进行字符串转换。
比如,alert(value)
将 value
转换为字符串类型,然后显示这个值
我们也可以显式地调用 String(value)
来将 value
转换为字符串类型:
js
let value = true;
alert(typeof value); // boolean
value = String(value); // 现在,值是一个字符串形式的 "true"
alert(typeof value); // string
字符串转换最明显。 false 变成 "false" , null 变成 "null" 等
数字型转换 number
在算术函数和表达式中,会自动进行 number 类型转换。
比如,当把除法 /
用于非 number 类型:
js
alert( "6" / "2" ); // 3, string 类型的值被自动转换成 number 类型后进行计算
我们也可以使用 Number(value)
显式地将这个 value
转换为 number 类型
js
let str = "123";
alert(typeof str); // string
let num = Number(str); // 变成 number 类型 123
alert(typeof num); // number
当我们从 string 类型源(如文本表单)中读取一个值,但期望输入一个数字时,通常需要进行显式转换
如果该字符串不是一个有效的数字,转换的结果会是 NaN
。例如:
js
let age = Number("an arbitrary string instead of a number");
alert(age); // NaN,转换失败
number 类型转换规则:
值 | 变成...... |
---|---|
undefined |
NaN |
null |
0 |
true 和 false |
1 and 0 |
string |
去掉首尾空格后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0 。否则,将会从剩余字符串中"读取"数字。当类型转换出现 error 时返回 NaN |
eg:
js
alert( Number(" 123 ") ); // 123
alert( Number("123z") ); // NaN(从字符串"读取"数字,读到 "z" 时出现错误)
alert( Number(true) ); // 1
alert( Number(false) ); // 0
- 注意
null
和undefined
在这有点不同: null 变成数字0
,undefined
变成NaN
大多数数学运算符也执行这种转换,将在下一节中进行介绍
布尔型转换 boolean
发生在逻辑运算中(将进行条件判断和其他类似的东西),也可以通过调用Boolean(value) 显式地进行转换
转换规则如下:
值 | 变成...... |
---|---|
0 , null , undefined , NaN , " "(只有空格的字符串) | false |
其他值 | true |
eg:
js
alert( Boolean(1) ); // true
alert( Boolean(0) ); // false
alert( Boolean("hello") ); // true
alert( Boolean("") ); // false
- 请注意:包含 0 的字符串 "0" 是 true
一些编程语言(比如 PHP)视 "0" 为 false 。但在 JavaScript 中,非空的字符串总是true
js
alert( Boolean("0") ); // true
alert( Boolean(" ") ); // 空白,也是 true(任何非空字符串都是 true)
基础运算符,数学
术语:"一元运算符","二元运算符","运算元"
- 运算元 ------ 运算符应用的对象。比如说乘法运算
5 * 2
,有两个运算元:左运算元 5 和右运算元 2 。
有时候也称其为"参数"而不是"运算元"。 - 如果一个运算符对应的只有一个运算元 ,那么它是 一元运算符。比如说一元负号运算符
-
,它的作用是对数字进行正负转换:
js
let x = 1;
x = -x;
alert( x ); // -1,一元负号运算符生效
- 如果一个运算符拥有两个运算元,那么它是 二元运算符:
js
let x = 1, y = 3;
alert( y - x ); // 2,二元运算符减号做减运算
数学
支持以下数学运算:
加法 +
,
减法 -
,
乘法 *
,
除法 /
,
取余 %
,
求幂 **
.
% 和 ** 需要详细说明
取余 %
取余运算符是 % ,尽管它看起来很像百分数,但实际并无关联
a % b 的结果是 a 整除 b 的 余数
例如:
js
alert( 5 % 2 ); // 1,5 除以 2 的余数
alert( 8 % 3 ); // 2,8 除以 3 的余数
求幂 **
求幂运算 a ** b 是 a 乘以自身 b 次
例如:
js
alert( 2 ** 2 ); // 4 (2 * 2,自乘 2 次)
alert( 2 ** 3 ); // 8 (2 * 2 * 2,自乘 3 次)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2,自乘 4 次)
求幂的定义也适用于非整数。例如,平方根是以 1/2 为单位的求幂:
js
alert( 4 ** (1/2) ); // 2(1/2 次方与平方根相同)
alert( 8 ** (1/3) ); // 2(1/3 次方与立方根相同)
用二元运算符 + 连接字符串
通常,加号 + 用于求和
但是如果加号 + 被应用于字符串,它将合并(连接)各个字符串:
js
let s = "my" + "string";
alert(s); // mystring
注意:只要任意一个运算元是字符串,那么另一个运算元也将被转化为字符串。
js
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"