系统地过一遍 JavaScript 基础语法及各种知识点。
声明变量
- ES 5:
var
- ES 6:
let
声明变量,const
声明常量。
变量提升 (hoisting)
JavaScript 引擎会先解析代码并获取所有使用 var
声明的变量并完成声明操作,再按顺序逐行运行。
注意 所有使用 var 声明的变量 包括了各种块级作用域的变量,如 for 语句或使用一对花括号声明的代码块 {}
。很明显这导致了这些本应只在局部生效的变量变成了全局变量。
在浏览器的 console 中运行以下代码 (example 1-1) 观察该问题:
1 | // example 1-1 |
运行结果解释:变量 var x 的声明操作被提升到脚本开头(但没完成初始化/赋值操作),因此第一次输出为 undefined, 第二次和第三次输出为正常内容。
代码的实际运行过程等同于:
1 | var x; // undefined, 注意不是 null |
总的来说,这段代码 (example 1-1) 包含了两个问题:使用未声明的变量没有报错,违反了先声明后使用的原则、局部变量在作用域以外调用没有报错。而这两个问题都是由 var
变量的提升导致的。
使用 let
关键字声明变量,而不是 var
关键字,则可以避免该问题:
1 | if (true) { |
改为 let
声明后,变量必须先声明才能使用,且作用域仅为当前代码块,结果符合预期。
全面使用 let 替代 var 关键字。
运算符
==
相等运算符,不同类型的元素会进行类型转换。===
严格相等运算符,元素进行比较时不会进行类型转换。
// TODO ES 6 补充
数据类型
- 数值 Number
- 字符串 String
- 布尔值 Boolean
- 空值 null
- 未定义 undefined
- 对象 Object
- Symbol (ES 6 新增)
其中 number, string, boolean 为基础数据类型,object 类型为复合数据类型。
Object 类型可以细分为三种子类:
- OOP 中的对象(狭义的对象)
- 数组 Array
- 函数 Function
类型判断
typeof
一元运算符,返回变量的类型 (String)instanceof
二元运算符:a instanceof Type
, 返回的结果为 true/false // TODOObject.prototype.toString
// TODO
1 | let a = 0; |
instanceof
运算符可以区别普通对象和数组:
1 | let a = {}; |
历史遗留问题
typeof null 结果为 Object
在变量的定义中,null 是与 Object 不同的数据类型。但在实际测试中发现 typeof null
返回的类型名为 Object。
这是因为在 JS 设计之初,作者没有深入考虑 null 的定义, 只把它作为 Object 的特殊形式。在 JS 的后续版本中 null 独立为单独的数据类型后,为了向下兼容,typeof null
仍为 object.
null 与 undefined 的问题
在 JS 语言设计之初,由于 C 语言的传统,null 可以自动转为 0:
1 | let n = Number(null); |
这可能会导致难以察觉的问题。因此 JS 作者又设计了 undefined
:
1 | let n = Number(undefined); |
undefined
的一些场景:
- 只声明但没有赋值的变量;
- 调用函数时没有传递相应的参数,则函数内部的参数为 undefined;
- 对象中不存在的属性;
1 | // case1 |
布尔值 boolean
在需要布尔值的位置,非 boolean 的对象会被转换为 boolean. 默认为 false 的类型:
undefined / null / 0 / NaN / ‘’ (空字符串)
数值 Number
JavaScript 内部使用 64 位浮点数形式存储数值类型。
1 | let a = 1; |
当需要以整数的方式进行计算时(如位运算),64 位的浮点数会被转换为 32 位的整数。
// TODO ‘位运算’章节补充
对于浮点数的处理,尤其需要注意精度。
1 | 0.01 + 0.02 === 0.03 // true |
建议尽量避免直接基于浮点数(数值类型)进行判断,而转化为字符串。
数值的进制
- 二进制:以
0b
或0B
为前缀 (b for binary); - 八进制:以
0o
或0O
为前缀(第二个字符为字母 o, 即 octonary); - 十六进制:以
0x
或0X
为前缀 (x for hexidecimal);
1 | // 二进制形式 |
特殊数值
正零和负零
只有符号位的区别。只有以正零或负零为分母时才会有区别(JS 允许分母为零):结果为 Infinity 或 -Infinity:
1 | 1/+0 // Infinity |
NaN
Not a Number 的缩写,主要出现在字符串转为数值,或数学运算结果。NaN 不是独立的数据类型,而是 Number 中的一个特殊值。
1 | 0 / 0 // NaN |
NaN 的运算规则:
- NaN 不等于它自身
- NaN 与任何数的运算结果均为 NaN
1 | NaN === NaN // false |
数值相关全局方法
isNaN
parseInt
parseFloat
isNaN(val): 判断参数是否为 NaN
1 | isNaN(); // true |
parstInt(string, radix)
将参数转换为十进制整数。第一个参数为待转换的元素(如 "1.00"
),第二个参数为第一个参数的进制,如果不传则默认第一个参数为十进制。
第二个参数的范围为 2-36, 最大值 36 由 0-9 及 a-z 按顺序组成。
1 | parseInt(10) // 10 |
数值处理的异常情况:
1 | // 开头的空格部分会被自动忽略 |
parseFloat(string, radix)
除了结果为浮点数,均与 parseInt
相同。
1 | parseFloat('15.0') // 15 |
字符串
长度属性:str.length
;以数组的方式获取单个字符:str[0]
;
转码:
btoa(asciiStr)
: 将 ascii 字符串转为 base64 编码atob(base64Str)
: 将 base64 编码内容转为 ascii 字符串