JS 红宝书笔记-变量 & 数据类型
变量
JavaScript 中有 3 个关键字可以声明变量:var
、const
和 let
。其中,const
和 let
只能在 ECMAScript6 及更晚的版本中使用
var 声明
-
var
声明的变量,存在变量提升function foo() { console.log(age) var age = 26 } foo() // undefined
-
使用
var
可以反复多次声明同一个变量function foo() { var age = 16 var age = 26 var age = 36 } foo() // 36
这是因为存在变量提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明
let 声明
-
let
声明的范围是块作用域if (true) { let age = 26 console.log(age) // 26 } console.log(age) // ReferenceError
age
变量之所以不能在if
块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集。 -
let
不允许同一个块作用域中出现冗余声明,会导致报错let age let age // SyntaxError; 标识符 age 已经声明过了
-
let
声明的变量不会在作用域中被提升console.log(age) // ReferenceError: age 没有定义 let age = 26
-
let
在全局作用域中声明的变量不会成为window
对象的属性 -
for
循环中的let
声明for (var i = 0; i < 5; i++) { setTimeout(() => console.log(i), 0) // 5 5 5 5 5 }
setTimeout
是一个异步操作,由于var
是全局变量,所以执行到这里拿到的是循环结束后的 i 的值,是同一个变量,因而输出的都是同一个最终值for (let i = 0; i < 5; i++) { setTimeout(() => console.log(i), 0) // 0 1 2 3 4 }
使用
let
声明迭代变量时,JS 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout
引用的都是不同的变量实例
const 声明
const
的行为与let
基本相同,唯一一个重要的区别就是它声明变量时必须同时初始化变量- 尝试修改
const
声明的变量会导致运行时错误,如果const
变量引用的是一个对象,修改这个对象内部的属性并不违反const
的限制 - 不允许重复声明
- 作用域是块
变量声明的最佳实践
- 不使用
var
限制自己只使用let
和const
有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值 const
优先,let
次之
使用const
声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。只在提前知道未来会有修改时,再使用let
。
数据类型
ECMAScript 有 6 种简单数据类型:
Number
String
Boolean
Undefined
Null
Symbol
还有一种复杂的数据类型:Object
typeof 操作符
typeof
可以返回的字符串如下:
number
string
boolean
undefined
object
function
symbol
可以看出,typeof
能判断简单数据类型(null 除外),可以判断是否为 Object,但是无法具体细分子类型
Undefined 类型
- 当使用
var
或let
声明了变量但没有初始化时,就相当于给变量赋值了undefined
值 - 一般来说,永远不用显式地给某个变量设置
undefined
值 - 对于未声明的变量、声明但未初始化的变量,
typeof
返回的都是"undefined"
Null 类型
null
值表示一个空对象指针- 在定义将要保存对象值的变量时,建议使用
null
来初始化,可以保持null
是空对象指针的语义
Boolean 类型
不同类型与布尔值之间的转换规则:
需要注意的是,空对象、空数组都是 truely
,也就是可以转换为 true
Boolean({}) // true
Boolean([]) // true
if
等流程控制语句会自动执行其他类型到布尔值的转换
let arr = []
if (arr) {
console.log('yes')
}
arr
为空数组,是 truely
变量,结果输出字符串 "yes"
Number 类型
Number
类型可以表示整数和浮点数。由于存储浮点数使用的内存空间是存储整数值的两倍,所以 ECMAScript
总是想方设法把值转换为整数
let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理
浮点数存在精度问题,不要直接进行比较
数值转换
Number()
可用于任何数据类型parseInt()
用于将字符串转换为数值
更专注于字符串是否包含数值模式。字符串最前面的空格会被忽略,从第一个非空格字符开始转换parseFloat()
用于将字符串转换为数值
String 类型
字符串转换
toString()
方法
可见于数值、布尔值、对象和字符串;null 和 undefined 没有toString()
方法String()
转型函数- 如果值有
toString()
方法,则调用该方法并返回结果 - 如果值是
null
,返回 "null" - 如果值是
undefined
,返回"undefined"
- 如果值有
Symbol 类型
- 用来创建唯一记号,进而用作非字符串形式的对象属性
- 只要创建
Symbol()
实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性