let与var的区别可以清晰地归纳为以下几点:
-
作用域不同:
var
是函数作用域,即在函数内部声明的var
变量,整个函数内部都是有效的。它也可以被声明在全局作用域中,此时整个脚本都可以访问到这个变量。let
是块作用域,它被声明在代码块(如 if 语句、for 循环等)内,并且只在该代码块内有效。一旦出了这个块,变量就无法被访问。
-
变量提升:
- 使用
var
声明的变量会发生变量提升,即变量会被自动“提升”到它们所在作用域的顶部,但赋值部分不会提升。这意味着变量可以在声明之前被引用,此时它的值是undefined
。 let
声明的变量不存在变量提升。如果在声明之前尝试访问let
变量,JavaScript 会抛出一个错误,处于暂存死区(Temporal Dead Zone, TDZ)的状态。
- 使用
-
重复声明:
- 在同一个作用域内,可以使用
var
重复声明同一个变量,此时后续的声明会覆盖前面的声明,而不会引发错误。 - 在同一个作用域内,不能使用
let
重复声明同一个变量,否则会抛出SyntaxError
错误。如果在全局和局部都声明了同一个变量那么全局变量会被覆盖。
- 在同一个作用域内,可以使用
-
全局对象属性:
- 在全局作用域中使用
var
声明的变量会成为全局对象(在浏览器中是window
)的属性。 let
在全局作用域中声明的变量不会成为全局对象的属性。
- 在全局作用域中使用
综上所述,let
和 var
的主要区别在于它们的作用域规则、变量提升行为、重复声明以及是否成为全局对象属性。了解这些差异有助于编写更清晰、更易维护的 JavaScript 代码,并减少因作用域和声明方式不当而引发的错误
简单const常量与复杂const常量:
在JavaScript中,const
用于声明常量,即一旦声明,其值就不可更改的变量。但是,“不可更改”这一说法需要根据const
所声明的数据类型来具体理解。我们可以将const
声明的变量分为“简单const
”和“复杂const
”,这里主要指的是它们所引用的数据类型是简单类型还是复杂类型。
简单const
当const
用于声明基本数据类型(如数字、字符串、布尔值等)时,这个变量就存储了实际的数据值,并且这个值是不可变的。例如:
JavaScript
const PI = 3.14159; PI = 3.14; // 报错:TypeError: Assignment to constant variable.
在这个例子中,PI
是一个常量,其值被设置为 3.14159
,并且不能被重新赋值。
复杂const
当const
用于声明复杂数据类型(如对象、数组等)时,情况就有所不同。const
保证的是变量指向的内存地址不变,而不是这个内存地址中存储的数据不可变。换句话说,你不能让复杂const
指向一个新的对象或数组,但你可以修改这个对象或数组内部的属性或元素。例如:
javaScript
const person = { name: 'Alice', age: 30 }; // 下面的操作是合法的,因为我们没有改变person变量指向的内存地址 person.name = 'Bob'; // 修改对象内部的属性是允许的 person.age = 35; // 同样允许 // 下面的操作是非法的,因为我们试图让person指向一个新的对象 person = { name: 'Charlie', age: 40 }; // 报错:TypeError: Assignment to constant variable.
对于数组也是同样的道理:
JavaScript
const numbers = [1, 2, 3]; // 下面的操作是合法的,因为我们没有改变numbers变量指向的内存地址 numbers.push(4); // 向数组中添加元素是允许的 numbers[0] = 0; // 修改数组中的元素也是允许的 // 下面的操作是非法的 numbers = [4, 5, 6]; // 报错:TypeError: Assignment to constant variable.
总结来说,简单const
和复杂const
的主要区别在于它们所引用的数据类型的可变性。简单const
引用的基本数据类型是不可变的,而复杂const
引用的复杂数据类型(如对象、数组)的内部结构是可以修改的,但不能改变其指向的内存地址。