4.2.2.3 JS 速成:顺序结构,变量与值,数组与对象
INFO
本文按照 Mozilla 贡献者基于 CC-BY-SA 2.5 协议发布的以下文章改编:
- https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps/What_is_JavaScript
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number
- https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps/Arrays
- https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Basics
本文假设你已经至少掌握一门编程语言,所以介绍非常简略,并且假设读者已经学会编程的各种概念。
JS 速成教程的内容大多来自本人以前写的 JS 入门教程,成文时间较早。如果发现有什么难懂的地方可以反馈。这个教程的定位是接触过编程语言,但是对具体有些理念还是不太清楚的人。如果你完全没接触编程,或者很清楚地掌握了编程,参考替代教程。
替代教程
如果你没有接触过编程,那么就需要完整学习 JS。可以完整阅读 MDN: JavaScript—— 动态客户端脚本语言中的所有教程,确保掌握 JavaScript。或者你也可以阅读 The Modern JavaScript Tutorial (英文) ,这是一篇比较标准的纯粹语言学习,没有 MDN 那么多互动环节。这些教程完整的涵盖了我本节提到的内容,所以看了就可以替代本节,当然时间就会拉长,也就没法速成 JS 了,对于编程语言而言,如果你没有学会一门编程语言,没有掌握编程语言的思维方式,还是有必要系统学习的。
如果你已经熟练运用 Python 等脚本语言,接触了脚本语言的各种概念和坑,那么你就可以直接快速阅读 The Modern JavaScript Tutorial (英文) 来了解 JS 语法和踩坑点,学完之后也推荐阅读一下 4.2.2.5 JS 速成:继承、DOM API 和异步,这篇是本人的经验之谈,希望能帮到大家。
环境要求
拥有一个可以交互式运行 JavaScript 的环境。可以是 Node.js 命令行,也可以是浏览器的控制台 (Console),在浏览器按 F12 打开开发者工具就可以找到。
我们的教程要求大家同步键入 JS 代码来交互式学习,提高效率。
对于完整的 JS 程序作业,如果不涉及浏览器提供的 API 的话,建议使用 Node.js 来运行 .js
文件。
node <name>.js
对于浏览器,使用我们前面提到的运行环境,加上 <script>
标签,即可加载 JS 文本并运行。具体可以查阅 MDN: 怎样向页面添加 JavaScript。
变量,值和顺序结构
语句和注释
在开始变量之前我们讲一下语句。JS 的语句是以英文分号 ;
结尾的,而不是换行,因为同一行内可以用分号隔开多条语句。虽然 JS 对于一个没有分号直接换行的语句会自动补上分号,但是最好不要这么做。为了防止自己出现这些问题,你可以给自己的 VSCode 装上相关的 Lint 插件。
注释可以写在代码里面,解释器会自动忽略它们。你可以用这些说明你的程序干了什么。JS 里面有着两种注释,一种是用 /* */
包裹的注释,一种是用 //
开头到一行结尾的注释。下面是两种注释的使用。后面我们会用到的。
/* 我是一行注释 */
// 我也是一行注释
/*
我可以跨行
*/
// 我只能
// 这么跨行
2
3
4
5
6
7
8
数据类型与基本运算
JS 里有七种基本数据类型,但是很多类型现在都用不到。所以我们就先讲下最常用的数字和字符串,以及一些基础的运算。
数字
在 JS 里面只有一个数字类型。不论这些数字是像 30(也叫整数)这样,或者像 2.456 这样的小数(也叫做浮点数),在内部都是用浮点数来表示的。这个和别的编程语言(比如 python)不同。这意味着 1
和 1.0
是同一个数字(而其他语言就是两个类型的数字)。
数字可以进行四则运算,优先级和数学里一样,你也可以加上括号改变优先级,就像在用计算器。乘号使用星号 ( *
) 代替,除号使用斜杠 ( /
) 代替。运算符两边可以加上空格,这样排版会更美观一点 (也许是)。
你可以打开浏览器的控制台运行你的 JS,也可以在本地安装 Nodejs ,使用 Node 来运行。我演示的时候使用的是 Node,因为可以直接在 VSCode 的控制台内输入 node
指令来打开。
下面是在 Node 中运行的结果,其中 >
表示这行是输入,输入紧跟着的下一行就是控制台的提示输出。注意实际的 JS 脚本在浏览器运行的时候是没有给每行加上一个输出的,你要用 console.log()
来进行。
> 1; // 1 就是 1
1
> -1; // -1 就是 -1
-1
> 1+1; // 就是一加一
2
> 1 + 1; // 加上空格之后运行结果也一样
2
> 1 * 2 + 2 * 3; // 运算符优先级和数学一样
8
> (1 + 2) * 3; // 使用了括号
9
> 6 / 3; // 除法
2
> 1.1 + 1.5; // 小数加法
2.6
> 0.1 + 0.2; // 这是浮点数误差导致的
0.30000000000000004
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
最后一个 0.1 + 0.2
算出来结果是 0.30000000000000004
(15 个 0 ,不用数了),这是怎么回事?这不是 bug,是语言的特性,叫做浮点数误差,是因为计算机在转换小数到二进制的时候丢失精度导致的 (可以看 https://0.30000000000000004.com/ 了解)。所以以后判断小数相等的时候可能不能直接用等号来进行。
除了四则运算之外,还有一种取余运算,使用百分号 ( %
)。在两者都是正数的时候,可以取得前一个数字除以后一个数字的余数。如果出现负数可能就不太一样,不过一般不会遇到,所以就先略过。
> 5 % 2;
1
> 5 % 3;
2
> 25 % 5;
0
>
2
3
4
5
6
7
有时候我们需要舍弃小数部分,这可以用 Math
的一些方法来进行。其中 Math.round()
四舍五入, Math.floor()
向下取整, Math.ceil()
向上取整。
> Math.round(3.1415926)
3
> Math.round(3.999)
4
> Math.ceil(3.1415926)
4
> Math.floor(3.999)
3
>
2
3
4
5
6
7
8
9
数字的范围是有限制的,超出限制的就无法精确表示。JS 能够准确表示的整数范围在 -2^53
到 2^53
之间(不含两个端点),超过这个范围,就无法精确表示这个整数。
如果一个式子不能被计算,那么它的值就会变成 NaN
( Not a Number,不是一个数字,最典型的就是给 -1 开平方,或者尝试给一个不全是数字的字符串转成数字。
> Math.sqrt(-1); // 给 -1 开平方
NaN
> parseInt("123"); // 正常的转换
123
> parseInt("Your life is which you loved"); //给字符转数字
NaN
>
2
3
4
5
6
7
字符串
另一个非常常用的就是字符串。顾名思义,这就是一串的字符。它可以用一对英文单引号( ''
)或者一对英文双引号 ( ""
) 包裹一串字符来表示,比如 '我是一个字符串'
"我是另一个字符串"
。
同样和别的语言不一样的是,JS 只有字符串类型,而没有单个字符类型。你可以用只有一个字符的字符串代替。
如果要在字符串里面包含特殊字符可以在字符前加上反斜杠 ( \
) 进行转义。比方说要包含引号的时候,就可以用 \"
或者 \'
来表示引号本身而不是字符串结尾。
你可以使用加号 +
来对字符串进行拼接操作,这可以得到这些字符串首尾相连的结果。
> "I am a str"; // 使用一对双引号
'I am a str'
> 'Another str'; // 一对单引号
'Another str'
> 'a'; // 单个字符的字符串
'a'
> '一个有引号\"的字符串'; // 转义
'一个有引号"的字符串'
> '也可以这样带上单引号:\'. '; // 也是转义
"也可以这样带上单引号:'. "
> "aa" + "bb"; // 拼接
'aabb'
> 'abc' + ' ' + 'def'; // 多个一起拼接
'abc def'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
转换
字符串和数字之间可以相互转换。这些转换通过一些 JS 内置的函数进行。有些是显式进行的(比如调用一个函数),有些是隐式进行的(比如让字符串和数字相加)。
一般情况下,涉及数字转字符串的我们采取隐式的方式。字符串转数字的时候我们使用 parseFloat()
和 parseInt()
函数来显式转换,用法是在括号内放一个字符串。 parseFloat()
的结果如果有小数会带上小数部分, parseInt()
的结果会直接去掉小数部分(而不是四舍五入)有关函数更为具体的内容我们以后会探讨,这里可以简单看作是一些封装起来的代码,执行之后返回一个结果。
下面我们来演示这些。
> "The answer is " + 42; // 一个拼接
'The answer is 42'
> 42 + " is the answer"; // 另一个拼接
'42 is the answer'
> "37" + 7; // 加法会把数字转成字符串
'377'
> "37" - 7; // 除了加法都会将字符串转成数字
30
> parseFloat("37") - 7; // parseFloat 的结果也一样
30
> parseFloat("123"); // 这里也是整数
123
> parseFloat("123.45"); // 小数部分也正常
123.45
> parseFloat("10e5"); // 还可以用科学计数法
1000000
> parseInt("123"); // parseInt 的整数转换
123
> parseInt("123.45"); // 现在去掉小数了
123
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
变量
变量本质上是值(例如数字或字符串)的容器,比如你可以用它去存一个数字 123
,也可以存一个 Hello world!
字符串。
变量可以通过这三个关键字声明:
let
: 这是在 ECMAScript 2015 里面添加的。我们建议如果没有支持旧浏览器的需求就使用它。var
: 这是旧的声明变量方式,现在也可以用,但是不推荐,因为var
可以被重复声明,这会导致很多问题。const
: 这是常量,声明之后不能修改。
最好不要使用 var,因为它可以被重复声明,如果不小心重复声明了一个变量,会导致问题问题。同时用 var 声明的变量会发生变量提升,产生更多难以预料的问题。
变量名在 JS 里面又叫做标识符。标识符是有规则的,必须以字母、下划线(_)或者美元符号($)开头,而不能是数字开头;但是后续的字符也可以是数字(0-9)。同时 JS 支持 Unicode 字符集(也就是你可以声明一个中文变量,虽然没啥用)。JS 是大小写敏感的,比如 aA
和 aa
就是两个变量。
除了上面的规则之外,你也不能使用 JS 的保留字给变量命名。保留字,即是组成 JavaScript 的实际语法的单词。比方说什么 if
, while
, for
这些。一般变量命名是不会和保留字重复的。
我们建议使用大小写驼峰命名法,也就是包含多个单词的变量名称的第一个单词开头小写,其余单词开头大写。比如我要命名一个 "My first name" 来存名字,变量名就可以写成 myFirstName
。
变量声明之后,默认的值是 undefined
。你可以通过比较一个变量是否等于 undefined
来判断变量是否初始化 (使用双等号 ==
或三等号 ===
来比较,例如 x === undefined;
)。直接在控制台里面打一个变量名可以输出变量的值,如果调用没有声明的变量会弹出一个错误。
非 const
变量在声明之后可以重新赋值。赋值使用单个等号,格式为 变量名 = 新的值;
。新的值可以是单个值,比如 x = 1;
也可以是一个表达式 x = 1 + 2;
, 或者 x = x + 1;
(给 x 加上 1)。
声明和赋值可以写在一起,比如 let x = 1;
就可以声明一个变量,值为 1
。
我们现在可以这样试着声明变量,下面是在 Nodejs 上运行的结果,当然浏览器也一样。(语句一定要加上分号,虽然没有分号也能运行,但是最好不要养成坏习惯):
> let myFirstName; /*声明了一个 myFirstName*/
undefined
> myFirstName; // 显示 myFirstName 的值
undefined
> var myValue; // 声明了一个 myValue
undefined
> myFirstName = "Steve"; /*给 myFirstName 赋值了 "Steve" */
'Steve'
> myFirstName;
'Steve'
> myValue = 1 + 1; /*给 myValue 赋值了 1 + 1,值是 2 */
2
> myValue;
2
> myValue = "aaa"; /*重新给 myValue 赋值了一个字符串 */
'aaa'
> myValue; /*现在 myValue 是一个字符串*/
'aaa'
> let myFirstName;// 这里重复声明没有通过,而是报错了
Uncaught SyntaxError: Identifier 'myFirstName' has already been declared
> var myValue; /*这里重复声明,而且通过了*/
undefined
> myFirstName;
'Steve'
> myValue; /*还保留原来的值*/
1
> const myConst; /*声明 const 一定要先初始化!*/
const myConst;
^^^^^^^
Uncaught SyntaxError: Missing initializer in const declaration
> const myConst = 2; /*声明了一个 const 变量*/
undefined
> myConst; /*打印 myConst 的值*/
2
> myConst = 3; /*尝试给 myConst 重新赋值,不被允许*/
Uncaught TypeError: Assignment to constant variable.
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
你也可以现在就打开浏览器的控制台输入这些,来进行尝试。上机实践对学习编程非常重要,不上机很多问题在纸上看看是没有结果的。
由于 JS 的一些奇怪问题,我们建议不能使用下面的方式:
> bad1 = "This is bad"; /*没有加上关键字,自动变成全局变量 */
'This is bad'
> bad1;
'This is bad'
> bad2 === undefined; /*这是一个没有声明的变量的正常行为*/
Uncaught ReferenceError: bad2 is not defined
> bad2 === undefined; var bad2 = 0; /* 先使用后声明,发生变量提升*/
true
> bad2;
0
> bad3 = 0; let bad3; /*所以要用 let*/
Uncaught ReferenceError: Cannot access 'bad3' before initialization
>
2
3
4
5
6
7
8
9
10
11
12
13
用 var
声明的变量会发生变量提升,相当于把声明语句往上挪到作用域的开头了。这没什么用,反而会造成一些问题,所以你应该尽量只用 let
来声明。
变量赋值之后就可以用来进行一系列运算,就和普通的值一样。
> let x = 2; // 声明+初始化
undefined
> let y = 3;
undefined
> x + y; // 进行四则运算
5
> x - y;
-1
> x + 10;
12
> let str1 = 'AAA'; // 声明了两个字符串
undefined
> let str2 = 'BBB';
undefined
> str1 + str2; // 尝试一些拼接操作
'AAABBB'
> x + ' ' + str1;
'2 AAA'
> str1 + " is Str1";
'AAA is Str1'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
输入和输出
不像其他语言,JS 最初是给浏览器设计的,直到现在这也是它的最主要用途,所以它和 DOM 深度绑定,信息几乎都是从 HTML 页面读取,输出也基本都是写在 HTML 当中,甚至没有标准化的输入和输出 (Node.js 环境提供了一个输入的回调函数)。由于我们现在还没学过对象 (Object),所以我们采用一些其他方式进行输入输出。
我们使用 console.log()
函数进行输出,这个函数会在控制台上留下一条信息。不仅可以给它一个字符串,也可以给它一个语句,比如 console.log(1 + 1);
输出 2。
对于输入,我们选择手动更改代码中的相关变量赋值来进行替代。这可能有点麻烦,不过在学了 DOM 之后就可以用更标准的方法进行。
最后 —— 顺序结构
我们了解了 JS 里面的数字和字符串类型,以及它们的基本运算和转换关系。
我们还了解了变量,它是一种容器,可以用来存放变量。变量在赋值之后可以进行一系列的操作,就像普通的值一样。
现在,你可以写一些小程序来进行一些简单的运算了。比如一个最简单的 A+B Problem,输出 a+b 的结果:
let a = 1;
let b = 1;
let c = a + b;
console.log(c);
2
3
4
试试写出类似的 A-B,A*B,然后按照我们之前 Hello world 的方式加到浏览器里面运行。
这里的程序就是一个典型的顺序结构,代码从上到下一步步运行,最后得出结果。这是程序的三大基本结构之一,另外两个分别是分支和循环,我们会在不久之后提到。了解三大基本结构之后,理论上你就可以写出一些真正能用的程序了。
数组
数组是一系列按顺序排列的值的集合。它可以一下子存下一系列的值,就相当于一些按顺序排列的变量。比如我们现在要去超市买东西,依次买了很多物品,并且记录了它们的价格。
数组包裹在一对中括号内 ( []
) ,里面的值按顺序排列,并且使用英文逗号进行分隔 ( ,
) 。可以通过在数组名后面加上一个 ( []
) ,然后在括号内使用通过从零开始的下标来找到对应的值。下面我们给出了一系列的例子。
> let shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];
undefined
> shopping; // 打印 shopping 数组
[ 'bread', 'milk', 'cheese', 'hummus', 'noodles' ]
> let price = [ 5.00, 3.50, 12.50, 15.00, 7.50];
undefined
> price; // 打印 price 数组
[ 5, 3.5, 12.5, 15, 7.5 ]
> shopping[0]; // 使用下标进行查找,从 0 开始到比长度小一的值(这里是 4)结束
'bread'
> price[0]; // price 的第一个元素
5
> price[100]; // 越界之后值会变成 undefined
undefined
> shopping[3];
'hummus'
> price[2] = 114; // 可以给对应的下标赋值,这里是 2,就是第三个
114
> price; // 可以看到第三个发生变化了
[ 5, 3.5, 114, 15, 7.5 ]
> shopping[2] = 1234; // 还可以给原来的赋值不同类型,就和普通变量一样
1234
> shopping;
[ 'bread', 'milk', 1234, 'hummus', 'noodles' ]
> let anEmptyArray = []; // 可以先声明一个空的数组,以后再往里面加东西
undefined
> anEmptyArray; // 现在它是空的
[]
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
数组里的值甚至可以是另一个数组,这叫做数组嵌套,下面演示了嵌套数组的行为。
> let random = ['tree', 795, [0, 1, 2]]; // 声明一个嵌套的数组
undefined
> random[2][1]; // 访问嵌套数组,第一个[]导航到数组,第二个继续导航
1
> random[0] = ['acacia', 'birch', 'spruce', 'oak']; // 赋值为一个数组
[ 'acacia', 'birch', 'spruce', 'oak' ]
> random; // 现在里面有两个嵌套数组了
[ [ 'acacia', 'birch', 'spruce', 'oak' ], 795, [ 0, 1, 2 ] ]
> random[0][2]; // 同样可以访问
'spruce'
> random[0][3] = ['oak leaves', 'oak log']; // 数组套了三层了
[ 'oak leaves', 'oak log' ]
> random[0][3][1]; // 访问到第三层的数组
'oak log'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
数组方法
length
最常用的数组方法,可能就是获取数组长度了。数组长度可以通过 length
方法来获取,就是在数组名之后加上一个 .length
,例如 sequence.length
就可以了解我们下面定义的数组的长度。
> let sequence = [1, 1, 2, 3, 5, 8, 13]; // 声明一个数组
undefined
> sequence.length; // 打印数组的长度
7
>
2
3
4
5
length 属性最常用的时候,就是循环遍历一个数组中的所有项目。比如说下面的这个代码:
let sequence = [1, 1, 2, 3, 5, 8, 13];
for (let i = 0; i < sequence.length; i = i + 1) {
console.log(sequence[i]);
}
2
3
4
我们以后会详细了解循环,但是这里先稍微提下这里主要干的事情:
- 在数组中的元素编号 0 开始循环。
- 在元素编号等于数组长度的时候停止循环。 这适用于任何长度的数组,但在这种情况下,它将在编号 7 的时候终止循环(还记得数组的编号是从 0 开始的吗?0 到 6 就是 7)。
- 对于每个元素,使用 console.log () 将其打印到浏览器控制台。
字符串和数组之间的转换
有时候你会需要把一个有规律的字符串转化成数组来处理数据,比方说这样的字符串
let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
显然,这里是用 ,
来分割的一系列单词。如果我们要把它转成一个数组,就可以用 split()
方法,它会对字符串进行处理,然后返回一个数组。方法的用法是在字符串之后加上一个 .split()
,在括号内指定分隔符(默认是空格)。
> let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
undefined
> let myArray = myData.split(','); // 转换成数组
undefined
> myArray; // 现在已经转成数组了
[
'Manchester',
'London',
'Liverpool',
'Birmingham',
'Leeds',
'Carlisle'
]
> myArray[2]; // 第三个
'Liverpool'
> myArray[myArray.length - 1]; // 最后一个
'Carlisle'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
如果要把数组转成对应的字符串,可以用相反的方法 .join()
,用法和前面的相同。(假设我们这里是紧跟着上面执行的)
> let myNewString = myArray.join(',');
undefined
> myNewString;
'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle'
>
2
3
4
5
添加和删除数组项
这里我们可以使用 push()
和 pop()
方法在数组尾部进行添加和删除元素。使用 push()
方法之后会返回新数组的长度,使用 pop()
方法之后会返回被删除的那个值。也许你可以用变量存下它们。
> let myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];
undefined
> myArray.push('Cardiff'); // 添加一个元素
7
> myArray;
[
'Manchester',
'London',
'Liverpool',
'Birmingham',
'Leeds',
'Carlisle',
'Cardiff'
]
> myArray.push('Bradford', 'Brighton'); // 添加两个元素
9
> myArray;
[
'Manchester', 'London',
'Liverpool', 'Birmingham',
'Leeds', 'Carlisle',
'Cardiff', 'Bradford',
'Brighton'
]
> let newLength = myArray.push('Bristol'); // 存下新的长度
undefined
> myArray;
[
'Manchester', 'London',
'Liverpool', 'Birmingham',
'Leeds', 'Carlisle',
'Cardiff', 'Bradford',
'Brighton', 'Bristol'
]
> newLength; // 现在的新长度
10
> myArray.pop(); // 删除最后一个元素
'Bristol'
> let removedItem = myArray.pop(); // 存下删掉的元素
undefined
> myArray;
[
'Manchester',
'London',
'Liverpool',
'Birmingham',
'Leeds',
'Carlisle',
'Cardiff',
'Bradford'
]
> removedItem; // 删掉的元素
'Brighton'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
采取这个方法我们可以模拟一个栈操作。栈是一种 LIFO(先进先出)的数据结构。通俗的讲起来就像是叠盘子,后面的叠在上面,拿的时候就拿走最上面的。最后叠的最先拿出来,就是一个先进先出了。以后我们会单独开章节讲数据结构,当作拓展的内容。
对象
我们刚刚提到了数组,这是一种按顺序存值的方法。它用途非常广泛,但是因为只能按下标找值,在有些时候可能会比较难用。比如现在我们要存一个人的相关信息,比如名字,性别,年龄,简介这些,如果用数组就会遇到一个难题:必须给这些信息确定一个顺序,规定第一个是名字,第二个是性别等等。这样写会带来理解上面的困难(一堆乱七八糟的数字可不是很好阅读的)。如果使用一系列的单一变量去存,会搞出一大堆变量。那么有没有更好的方法呢?答案是使用对象。
对象 (Object) 是包含一系列相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)。由于我们目前还没有讲函数,我们暂时先讲对象的数值相关的东西,以后在函数部分再提对象的方法。
对象使用一对大括号 ( {}
) 来表示,里面包含着很多用逗号分开的成员,每一个成员都拥有一个名字(下面的 name, age 这些),和一个值(如 ["Linus", "Torvalds"], 52 都是值)。每一个名字和值 (Name and Value) 之间由冒号(:)分隔,然后就可以通过成员的名字来查找对应的值。下面是一个例子。为了看得更清楚,我们在其中插入了换行,一行一个成员。我们推荐在以后编程实践当中适当使用换行,因为可以让代码更加整洁。
let person = {
name: ["Linus", "Torvalds"],
age: 52,
gender: 'male',
saying: 'NVIDIA, **** YOU!'
};
2
3
4
5
6
可以使用点表示法来查找对应的值,就是在对象标识符之后加上一个点,在点后面加上键名称就可以了,比如 person.age
就可以对应 person
的 age
对应的值,即 52
。
还有另一种表示法是括号表示法,用法类似数组,是在一个中括号 []
内加上键名称来对应的,例如 person["saying"]
就可以对应到那个 saying
。
我们建议使用点表示法,因为更加简洁,方便打字。
下面是在 NodeJS 里面运行的结果,换行之后那三个点是 node 加上的,表示上一句话还没结束。这不是代码的一部分,所以自己写代码的时候不要加上去。
> let person = {
... name: ["Linus", "Torvalds"],
... age: 52,
... gender: 'male',
... saying: 'NVIDIA, **** YOU!'
... };
undefined
> person;
{
name: [ 'Linus', 'Torvalds' ],
age: 52,
gender: 'male',
saying: 'NVIDIA, **** YOU!'
}
> person.age; // 点表示法
52
> person['saying']; // 括号表示法
'NVIDIA, **** YOU!'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
子命名空间
可以用一个对象来做另一个对象成员的值。比如我们现在可以把 person
的 name
从一个数组换成一个对象。就像是下面这样。
let person = {
name: {
firstName: 'Linus',
lastName: 'Torvalds'
},
age: 52,
gender: 'male',
saying: 'NVIDIA, **** YOU!'
};
2
3
4
5
6
7
8
9
这样就可以用点表示法进行多重的查找,比如 person.name.firstName
这样子
> let person = {
... name: {
..... firstName: 'Linus',
..... lastName: 'Torvalds'
..... },
... age: 52,
... gender: 'male',
... saying: 'NVIDIA, **** YOU!'
... };
undefined
> person.name.firstName;
'Linus'
> person.name.lastName;
'Torvalds'
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这样非常有用,因为你可以在对象里面嵌套另一个对象,从而有结构地保存一系列的数据,起到方便阅读和维护的作用。
设置对象成员
有时候我们需要对对象进行一系列的操作。比方说我们可能会修改一个成员,可能会加上一个还没有的成员,或者一个成员不要了我们可以删除它。这些都是可以做到的。
现在我们再创建一次上文中的 person
对象,然后对这个变量进行一系列操作:
let person = {
name: ["Linus", "Torvalds"],
age: 52,
gender: 'male',
saying: 'NVIDIA, **** YOU!'
};
2
3
4
5
6
现在你可以试着修改其中的成员:
> person.name = 'Tux'; // 设置名字
'Tux'
> person.age = 25; // 设置年龄
25
> person; // 现在已经变化了
{ name: 'Tux',
age: 25,
gender: 'male',
saying: 'NVIDIA, **** YOU!' }
>
2
3
4
5
6
7
8
9
10
你可以删除其中的成员
> delete person.saying;
true
> person; // 现在已经成功删除了
{ name: 'Tux', age: 25, gender: 'male' }
>
2
3
4
5
还可以直接添加原来没有的成员
> person.newValue = 123;
123
> person; // 可以看到直接加上了一个值
{ name: 'Tux', age: 25, gender: 'male', newValue: 123 }
>
2
3
4
5
方法
其实对象远远比我们现在讲的要复杂多了,比如对象的成员可以不只是一个普通的值,还可以是函数 (事实上这个才是对象里面用的最多的)。关于函数的定义比较复杂,现在你可以认为是一组执行任务或计算值的语句。在对象里面作为的函数叫做这个对象的方法。
下面我们看下这个例子,我们给它添加了一个用来在控制台进行输出的方法。
person.say = function (){
console.log("Hello, I am " + this.name + ".");
};
2
3
在 NodeJS 中运行。
> person.say = function (){
... console.log("Hello, I am " + this.name + ".");
... // 这里的 this 指的是当前的对象,相当于外面用 person.name
... };
[Function]
> person.say; // 这里不是调用函数,而是会指向函数本身
[Function]let cat = {
name: "Ket",
say: function() {
console.log("My name is " + this.name);
}
}
cat.say();
> person.say(); // 要加上括号才能调用,现在输出了内容
Hello, I am Tux.
undefined
>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
可以看到我们让 person
对象输出了自己的名字。简单地说我们干了这几件事情:
- 使用 function 关键字表明下面是一个函数
- 在函数里定义了一条
console.log()
语句,向控制台输出。 - 用 this 定位到自己本身,然后把自己的名字拼接到字符串内
- 使用
person.say()
来进行输出。
所以我们之前遇到的很多东西 (例如本章讲的 push()
pop()
或者刚刚用到的 console.log()
) 其实都是方法。有关于函数的内容我们会在以后详细地了解。
小结
我们了解了数组和对象。
数组是一种按顺序保存一系列值的数据结构,声明的时候用一对的中括号 []
来表示,其中可以包含用逗号分隔的值。
数组的每个元素可以采用下标进行查找,下标范围从 0 开始到比长度小一的值结束,你可以用 length
来获取长度。
数组和字符串之间可以使用 split()
和 join()
方法进行相互转换。
可以用 push()
在数组末尾加入值,也可以用 pop()
来删除末尾的值。
对象通过一对大括号 {}
来声明,里面用逗号分隔每一个成员。成员是由 名字: 值
的配对组成的。
对象的成员可以用点表示法查找,也可以使用括号表示法。
对象的成员就像一个普通的变量,可以进行修改。如果给一个原本没有的成员进行赋值,会添加一个新的成员。 对象的成员可以是函数,这也叫做方法。
练习
罗辑经常会忘记自己在谈的对象的名字,因此要你去用对象去记录她们的信息。现在他给你了一些信息,要你马上拿一个对象存起来。记住,只能用一个对象存。(名字都是《三体》书里抄的)
要求声明一个 girls
对象,将变量存到同名的成员内,然后使用 console.log()
输出对象。
let name1 = "张珊"
let name2 = "陈晶晶"
2
下面是一个数组,你需要把其中的第二项和第四项交换,然后输出数组。(注意下标从零开始)
let myArray = [ 1, 4, 3, 2, 5, 6, 7];