变量声明
var、let、const 的作用域与提升行为有何不同?
| 关键字 | 作用域 | 提升行为 | 重复声明 | 全局绑定 |
|---|---|---|---|---|
var | 函数作用域 | 提升声明并初始化为 undefined | 允许 | 浏览器中挂到 window |
let | 块作用域 | 提升但不初始化, 访问抛 ReferenceError | 禁止 | 不挂到 window |
const | 块作用域 | 同 let | 禁止 | 不挂到 window |
console.log(name); // undefined; var 已提升
var name = "Jake";
console.log(age); // ReferenceError; 暂时性死区
let age = 26;
- 混合声明冲突: 同一作用域内
var与let声明同名标识符均抛SyntaxError, 冲突取决于作用域而非关键字; - 使用原则: 少用
var, 优先const, 需要重新赋值时才用let;
const 声明有什么限制与优势?
- 必须初始化:
const声明时就要给出值; - 绑定不可变: 不能重新赋值, 但对象内容仍可修改;
- 优化空间: 常量更容易被引擎内联替换, 省去运行时查表;
标识符有哪些命名与保留字规则?
- 命名: 大小写敏感, 由字母、下划线、
$、数字组成, 且不能以数字开头, 变量用小驼峰, 常量用大写加下划线; - 关键字: 如
break、class、const、function、typeof、var、with等, 不能作为标识符; - 保留字: 如
enum、implements、interface、package、private、protected、public、static、let、await等, 为未来语义保留;
循环中声明变量为什么推荐 let?
var版本: 整个循环共用一个变量, 回调异步执行时读到循环结束后的值;let版本: 每轮迭代创建新的绑定, 各回调引用不同变量;const: 不能用作需要自增的循环迭代器;
for (var i = 0; i < 5; ++i) setTimeout(() => console.log(i), 0); // 5 5 5 5 5
for (let j = 0; j < 5; ++j) setTimeout(() => console.log(j), 0); // 0 1 2 3 4
同名变量与同名函数冲突时以谁为准?
- 同名变量: 后声明被忽略;
- 同名函数: 后声明覆盖先声明;
- 函数与变量同名: 函数提升早于变量, 但变量赋值会覆盖, 最终以赋值结果为准;
var a = undefined;
function a() {}
a(); // TypeError; 此时 a 已被赋值为 undefined
不声明就赋值会发生什么?
- 非严格模式: 自动成为全局对象属性 (浏览器为
window), 等价于隐式创建全局变量; - 严格模式: 直接抛错;
- 结论: 始终显式声明变量;