JS学习记事
JavaScript
对着这个教程进行学习,下面的内容主要是本人总结,不一定到位,仅作理解上的记录。
介绍
首页放着对JavaScript的介绍,实则和说明书一般,似乎是不用读的,读了一遍,确实不用读。
最后介绍了一个JS版本的Hello World代码,这是比较新颖的,分析一下,function定义了一个无名函数,"use strict"使用严格模式,紧接着是一个内部函数greetMe,后面调用传入世界后,浏览器弹出显示“你好世界”的提示框。
1 | (function () { |
语法
注释
简单来说,JS的语法区分大小写,同时一条指令后需要加入;作为分隔,虽然在某些情况可以省略,但好习惯当然可以减少报错。
单个语句独占一行则可以省略分号;单行多条语句则需用分号进行分隔。
注释这块没有什么独特的地方就是了,一眼可以扫过。
1 | // 单行注释 |
变量与作用域
JavaScript 有三种变量声明方式,var,let,const,区别如下示例所示。
首先是let和const,如下。
1 | //let 与 const 仅在对应的代码块{ }内可以访问。 |
对于var来说,访问的边界不再是代码块而是当前函数,倘若在函数外定义,则访问边界更广。
1 | // var 不以 if 的代码块为作用域边界,因当前在函数内故以函数为边界。 |
注:应该总是在声明变量后使用它们。JavaScript 过去允许给未声明的变量赋值,而这会创建一个未声明的全局变量。这在严格模式下是一个错误,应该彻底避免使用它。
可以使用解构语法声明用于解包值的变量,如’const { bar } = foo’,这会创建一个名为 bar 的变量,并且将 foo 对象中属性名与之相同的属性的值赋给它。
声明和初始化
let x = 42中的let x是声明,= 42是初始化器。
本质上,let x = 42等价于let x; x = 42。也就是说后赋值是允许的,除了const,const声明总是需要初始化器,必须使用const y = 123,否则将会报错。
变量提升
这是一个比较神奇的点,var声明会被提升,也就是说在进入一个作用域(如函数或者全局)时,var声明会被提到该作用域的顶部,先被声明且赋值undefined,如下示例详解。
1 | console.log(x === undefined); // true |
这份代码由于var声明的提升会被等价于下面的代码。
1 | //因为进入该域后先执行声明,于是变成var在前,但并不是实际代码内容变化,只是处理逻辑的展示。 |
这段代码存在两个x,但变量查找遵循作用域规则:先找当前作用域,找不到再向外找。也就是内部变量始终优先。
最后要说的是,let和const变量不提升,同时因为这个处理顺序,所以var声明越靠前越有利于代码易读性提升。
全局变量
前面提到var的作用域取决于申明的作用域,倘若于代码伊始声明则你会获得一个全局变量,同时浏览器提供了一个叫window的全局对象,你也可以通过window.变量名来访问,示例如下。
1 | <script> |
但是顶层的let和const不会成为window的属性,下同globalThis,但可以全局访问,且需要遵守作用域规则。
1 | let city = "广州"; |
浏览器使用window,Node.js没有浏览器的window。为了让代码跨环境使用,可以写globalThis,globalThis是不同环境中访问全局对象的统一入口。
1 | console.log(globalThis === window); // true |
最后是子页面访问父页面的属性,这里要提到iframe,可以理解为“网页里嵌入的另一张网页”,分别称父页面和子页面,它们各有自己的 window。引用时在父子页面同源、没有额外沙箱限制的情况下,可以实现以下示例的用法。
1 | <!-- 父页面 main.html --> |
变量使用规范
不能使用与变量名或函数名相同的名字来声明常量,错误的示例如下。
1 | // 这会造成错误 |
用const声明的变量不能重新赋值,但如果它指向一个对象,这个对象的属性仍然可以修改。
1 | // 变量 MY_OBJECT:受 const 限制,不能重新赋值。 |
这个规则同样适用于数组。
1 | const MY_ARRAY = ["HTML", "CSS"]; |
数据结构和类型
数据类型
最新的 ECMAScript 标准定义了 8 种数据类型:
七种基本数据类型:
- Boolean。
true和false。 - null。表示空值的特殊关键字。注意大小写。
- undefined。一个未定义值的顶级属性。
- Number。整数或浮点数。例如,42 或 3.14159。
- BigInt。任意精度的整数。例如,9007199254740992n。
- String。表示文本值的字符序列。例如,”Howdy”。
- Symbol。其实例是唯一且不可变的数据类型。
此外还有Object。
函数也可以算得一个基本元素,总的来说,数据类型决定你的对象放什么数据集,而函数利用这些对象执行任务。
数据类型的转换
JS是一门动态类型语言,所以在申明时不必指定该变量的数据类型,也就是说脚本会自动根据你存入的数据改变数据类型。
1 | let answer = 42; |
数字和“+”运算符
再带上+的运算符表达式中如果涉及到数字和字符串,JS则会把数字转换为字符串,示例如下。
1 | x = "答案是 " + 42; // "答案是 42" |
但在其他运算符使用时,JS不会把数字转换成字符串,示例如下。
1 | "37" - 7; // 30 |
+的加法用法将在下面讲到。
字符串转换为数字
首先需要讲到,如果想正确使用+,则需要先确保两边都是数字,字符串形式的数字可以使用Number()转换,示例如下。
1 | const x = "37"; |
但需要注意顺序为先转换后相加,否则。
1 | Number("37") + Number("7"); // 44 ✅ |
你也可以使用parseInt()和parseFloat(),它们会提取整个字符串开始的数字,遇到非数字则停止。其中parseInt()只返回整数,因此它在处理小数时用途有限,示例如下。
1 | // Number():转换整个字符串 |
字符传转换为数字的另一种方法则是使用+本身,示例如下。
1 | "1.1" + "1.1" = "1.11.1" |
字面量
简单来说就是赋值时=后你希望变量应该被赋予的值,如let a = 18,18就是数字字面量。常见的字面量如下。
- 数组字面量
- 布尔字面量
- 数字字面量
- 对象字面量
- RegExp 字面量
- 字符串字面量
按顺序进行解释如后。
数组字面量
JS的数组满足常见语言中的数组定义形式,所以字面量由一对方括号[]括起来的包含零个或多个表达式的列表,每个表达式代表一个数组元素。使用数组字面量创建数组时,会以你指定的值进行初始化,数组的length指定为数组的元素个数。
1 | // 这个示例展示了一个含有3个元素的 coffees 数组,其长度为3。 |
但需要注意的是,在不同位置执行数组字面量时,会出现读取或新建的不同操作,示例如下。
1 | // 对于这个示例来说,因为字面量创建于函数外,↓ |
第二个示例如下。
1 | // 对于这个示例来说,因为字面量创建于函数内,↓ |
简单理解就是每次只要执行[1,2,3]字面量操作,就是在新建数组,而函数被调用两次则分别新建了两个不同的局部变量numbers,所以也不能简单看作是同一个函数中出现两次对同一个变量的定义。
可由此判断数据是“每次重新开始”,还是“保留并共享之前的修改”,避免程序出现意外结果。
如果你在数组字面量中连续放置两个逗号,数组会为未指定的元素留下一个空槽;而如果在元素列表的尾部添加了一个逗号,这个逗号不会增加元素。如下面示例所展示,但尾部逗号可以保持代码形式整齐。
1 | const fish = ["Lion", , "Angel"]; |
布尔字面量
很常见的true和false.
数字字面量
JavaScript 数字字面量包括多种进制的整数字面量和仅十进制的浮点数字面量。
- 十进制整数字面量由数字序列组成,且没有前缀 0(零)。
- 八进制的整数字面量以 0(或 0O、0o)开头,只能包括数字 0-7。
- 十六进制整数字面量以 0x(或 0X)开头,可以包含数字(0-9)和字母 a-f 或 A-F。(字符的大小写不影响数值。因此,0xa = 0xA = 10 和 0xf = 0xF = 15。)
- 二进制整数字面量以 0b(或 0B)开头,只能包含数字 0 和 1。
- BigInt 由整数字面量和 n 后缀组成。BigInt 也可以使用上面的基数。注意前缀零的八进制语法(例如,0123n)是不允许的,但 0o123n 是可以的。
浮点数字面量
由这些部分组成:
- 一个无符号的十进制整数
- 小数点(
.) - 小数部分(另一个十进制数)
- 指数部分(指数部分以
e或E开头,后面跟着一个整数,这个整数可以有正负号(即前缀+或-)
浮点数字面量至少有一位数字,而且必须带小数点或者 e(E),示例如下。
1 | 3.1415926 |
对象字面量
对象字面量是由一对花括号({})括起来的包含零个或多个属性名和相关值的列表。
但建议不要在一条语句的开头使用对象字面量,这时
{可能会被识别为一个语句块的起始。
下面是简单的对象字面量示例。
1 | const sales = "Toyota"; |
更进一步,我们还可以使用数字或字符串字面量作为属性的名字,或者在另一个对象字面量内嵌套一个对象字面量。如下所示。
1 | const car = { manyCars: { a: "Saab", b: "Jeep" }, 7: "Mazda" }; |
从合法命名的角度出发,如果我们的对象属性名字不是合法的 JavaScript 标识符或数字,它必须用引号包裹。此时我们的属性名不合法,不能用(.)来访问该属性值,而是通过方括号表示法([])来访问。
1 | const unusualPropertyNames = { |
增强的对象字面量
对象字面量支持一些很新潮的用法,示例如下。
1 | const obj = { |
RegExp 字面量
正则式字面量是字符被正斜杠围成的表达式,如下示例所示。
正则式,用特殊符号表示一类字符或重复次数,主要用语字符串匹配。
1 | const re = /ab+c/; |
字符串字面量
字符串字面量是由一对双引号(")或单引号(')括起来的零个或多个字符。字符串被限定在同种引号之间(也即,必须是成对单引号或成对双引号)。
1 | 'foo' |
你可以在字符串字面量值上使用 String 对象的所有方法,JavaScript 会自动将字符串字面量转换为一个临时字符串对象,调用该方法,然后废弃掉那个临时的字符串对象。你也可以使用字符串字面量的 length 属性。(但需要区分字符串字面量与 String 对象)
1 | // 将打印字符串中的字符个数(包括空格) |
模板字面量
模板字面量(Template Literal)是 JavaScript 里用反引号 ` 包裹字符串的写法。它和普通字符串最大的区别是:可以插值、可以换行、还能加标签函数。
1 | //常规字符串 |
有时未定义的toString用法会导致讨厌的 [object Object],示例如下。
1 | const age = 18; |
示例二,这里我们通过自定print函数来避免讨厌的 [object Object]。
1 | const formatArg = (arg) => { |
控制流与错误处理
块语句
块由一对花括号{}界定,常用来组合语句,如控制流语句(if、for、while)。
1 | while (x < 10) { |
前面已经提过,不同变量的作用域不同,其中块就是一个作用域界。





