ES6 - 变量
ES6+ - 变量和作用域
Section titled “ES6+ - 变量和作用域”变量是内存中一个命名的存储位置,用于存放值。在 JavaScript 中,变量名(或标识符)必须遵循以下规则:
- 不能是保留关键字(例如,
if、for、function)。 - 可以包含字母、数字、下划线(
_)和美元符号($)。 - 不能以数字开头。
- 区分大小写(
myVariable和MyVariable是不同的)。
变量声明: var、let 和 const
Section titled “变量声明: var、let 和 const”在 ES6 之前,变量使用 var 关键字声明。ES6 引入了 let 和 const,用于更健壮的变量声明和作用域管理。
var (ES6 之前):
Section titled “var (ES6 之前):”使用 var 声明的变量具有函数作用域或全局作用域,它们不具有块级作用域。var 声明会被提升(参见变量提升部分)。
var globalVar = "I'm global";
function exampleFunctionVar() { var functionScopedVar = "I'm function-scoped"; console.log(functionScopedVar);
if (true) { var blockVar = "I'm declared in a block, but still function-scoped with var"; console.log(blockVar); } console.log(blockVar); // 由于函数作用域,这里可访问}exampleFunctionVar();// console.log(functionScopedVar); // 错误:functionScopedVar 在全局未定义let (ES6+):
Section titled “let (ES6+):”使用 let 声明的变量是块级作用域(block-scoped)。这意味着它们只能在其定义的块(例如,if 语句中的 {...}、for 循环或独立的块)内访问。let 声明会被提升(hoisted),但不会被初始化,这导致了暂时性死区(Temporal Dead Zone - TDZ)。
let globalLet = "I'm global (using let)";
function exampleFunctionLet() { let functionScopedLet = "I'm function-scoped (using let)"; console.log(functionScopedLet);
if (true) { let blockScopedLet = "I'm truly block-scoped!"; console.log(blockScopedLet); // 可访问 } // console.log(blockScopedLet); // 错误:blockScopedLet 在这里未定义}exampleFunctionLet();const (ES6+):
Section titled “const (ES6+):”使用 const 声明的变量也具有块级作用域,类似于 let。然而,const 声明必须在声明时初始化,并且其值不能被重新赋值。这意味着变量标识符不能指向一个新的值。
重要提示:const 并不会使值本身不可变(immutable)。如果 const 变量持有的是一个对象(object)或数组(array),则该对象的属性或数组的元素仍然可以被修改。
const PI = 3.14159;// PI = 3.14; // 错误:赋值给常量变量。
const person = { name: 'Alice', age: 30};person.age = 31; // 这是允许的!修改对象的属性。console.log(person.age); // 31
// person = { name: 'Bob', age: 40 }; // 错误:不能重新赋值 const 变量 'person'。
const numbers = [1, 2, 3];numbers.push(4); // 允许console.log(numbers); // [1, 2, 3, 4]// numbers = [5, 6]; // 错误初始化是将一个初始值赋给变量的过程。它可以在声明时完成,也可以稍后完成(对于 var 和 let)。const 要求在声明时必须进行初始化。
let name; // 声明name = "Alice"; // 初始化
let city = "London"; // 声明并初始化
const country = "UK"; // 声明并初始化 (const 必须同时进行)JavaScript 与动态类型
Section titled “JavaScript 与动态类型”JavaScript 是一种动态类型(dynamically-typed)语言。这意味着你在声明变量时不必指定其数据类型,并且变量的类型可以在程序执行期间改变。
let myVar = 42; // myVar 是一个数字console.log(typeof myVar); // "number"
myVar = "Hello, world!"; // myVar 现在是一个字符串console.log(typeof myVar); // "string"
myVar = true; // myVar 现在是一个布尔值console.log(typeof myVar); // "boolean"作用域(Scope)决定了变量的可访问性(可见性)。JavaScript 有几种类型的作用域:
- 全局作用域(Global Scope): 在任何函数或块之外声明的变量具有全局作用域。它们可以在 JavaScript 代码的任何地方访问。在浏览器中,用
var声明的全局变量会成为window对象的属性。用let和const在全局声明的变量则不会。 - 函数作用域(Function Scope / Local Scope): 使用
var、let或const在函数内部声明的变量仅在该函数内部可见,不能从外部访问。 - 块级作用域(Block Scope): 使用
let或const在块(例如,if、for语句中的{},或仅一个独立的块)内部声明的变量仅在该块内部可访问。
示例: 全局作用域、局部作用域与块级作用域
Section titled “示例: 全局作用域、局部作用域与块级作用域”const globalNum = 10;
function checkScope() { const functionNum = 100; console.log('Inside function - globalNum:', globalNum); // 10 console.log('Inside function - functionNum:', functionNum); // 100
if (true) { const blockNum = 200; console.log('Inside block - globalNum:', globalNum); // 10 console.log('Inside block - functionNum:', functionNum); // 100 console.log('Inside block - blockNum:', blockNum); // 200 } // console.log(blockNum); // 错误:blockNum 在这里未定义 (在其块外部)}
console.log('Outside function - globalNum:', globalNum); // 10// console.log(functionNum); // 错误:functionNum 在这里未定义 (在其函数外部)checkScope();变量遮蔽(Shadowing):如果你在某个作用域(例如,函数或块)内声明了一个与外部作用域中变量同名的变量,则内部变量在其作用域内会“遮蔽”外部变量。
变量提升 (Hoisting)
Section titled “变量提升 (Hoisting)”变量提升(Hoisting)是 JavaScript 的默认行为,它会将声明(declarations)移动到其各自作用域(全局、函数或块)的顶部,然后再执行代码。但是,只有声明会被提升,初始化(initializations)不会。
var 的变量提升:
Section titled “var 的变量提升:”使用 var 声明的变量会被提升到其函数作用域或全局作用域的顶部,并且会被初始化为 undefined。
console.log(hoistedVar); // undefined (声明被提升,初始化为 undefined)var hoistedVar = "I am hoisted!";console.log(hoistedVar); // "I am hoisted!"
// 在内部,上面代码的处理方式类似于:// var hoistedVar; // 声明被提升并初始化为 undefined// console.log(hoistedVar);// hoistedVar = "I am hoisted!";// console.log(hoistedVar);let 和 const 的变量提升 (暂时性死区 - TDZ):
Section titled “let 和 const 的变量提升 (暂时性死区 - TDZ):”使用 let 和 const 声明的变量也会被提升到其块级作用域的顶部,但它们不会被初始化。在声明之前(定义变量的那一行代码)访问 let 或 const 变量会导致 ReferenceError。从块的开始到遇到声明之间的这段时间被称为该变量的暂时性死区(Temporal Dead Zone - TDZ)。
// console.log(tdzLet); // ReferenceError: Cannot access 'tdzLet' before initialization (TDZ)let tdzLet = "In TDZ until here";console.log(tdzLet); // "In TDZ until here"
// console.log(tdzConst); // ReferenceError: Cannot access 'tdzConst' before initialization (TDZ)const tdzConst = "Also in TDZ";console.log(tdzConst); // "Also in TDZ"- 默认情况下,优先使用
const声明值不会被重新赋值的变量。 - 对于需要重新赋值的变量,使用
let。 - 在现代 JavaScript 中,避免使用
var,以防止其函数作用域和变量提升行为带来的问题。 - 为了提高可读性,即使存在变量提升,也最好在变量所属作用域(函数或块)的顶部声明变量。