var是什么意思?揭秘JavaScript中的变量声明
在JavaScript中,变量是用来存储数据的容器。这些数据可以是数字、字符串、布尔值或其他任何类型。从开始学习JavaScript时,我们就被教导如何使用var关键字来声明一个新的变量。那么,var是什么意思?它与其它两种声明变量的方式:let和const有什么区别?
var的历史
当JavaScript诞生之初,它并没有像今天这样多样化的特性。当时,开发者们只能使用单一的方法来声明和初始化变量,那就是通过关键字 var. 这个词来自于C语言中的“variable”,意为可变化的事物。在那个时代,没有人能够预见到未来 JavaScript 将会发展成什么样子。
var是什么意思?
简单来说, `var 是 JavaScript 中的一个关键字,用来在函数作用域内申明一个或多个标识符(通常是一个名字)。这个名字后面跟着赋值操作符等号(=)和要分配给该名称的一个值。这意味着你可以将任何类型的数据赋予给你的新创建出来的一个名为x 的地方。
// 使用 var 声明一个 变量
var x = 10;
let 和 const 的出现
随着时间推移,对于编程语言来说,这样的行为变得过时了。在2015年发布ES6规范之后,让我们有了两个全新的关键字:let 和 const. 它们提供了更好的功能,使得我们的代码更加清晰、安全,并且易于理解。
let: 在块级作用域内申明一个标识符。
const: 在块级作用域内申明一个常数,即不能重新赋值。
这两个新语句解决了一些老问题,比如说,在循环或者条件判断中重复声明同名的变量,以及无法阻止对象属性被重新分配的问题。
var vs let vs const 比较表格
| 关键词 | 作用域 | 可以改变吗? |
|--------|--------|--------------|
| var | 函数范围内 | 是 |
| let | 块级范围 | 是 |
| const | 块级范围 | 否 |
作用域规则
让我们深入探讨一下它们对应不同的作用域规则:
函数内部 - Var
当你把一个变量定义为局部的时候,如果你试图访问全局上下文中的同名元素,你将得到全局版本,而不是局部版本。如果你的函数已经执行完毕,那么所有由该函数所创建但未被销毁掉的本地对象都会被垃圾回收器处理掉。这意味着,当函数执行完成后,就不会再存在这些本地对象了,但如果某个外部环境中仍然保持对这个本地对象引用的状态,那么这个引用就不会被删除,因为外部环境还需要它。这种现象叫做"悬挂引用"(dangling reference)。
function outer() {
// 定义在这里,所以这是外层环境下的 myVar.
// 如果尝试访问 inner 中定义相同名称,则获取的是 outer 环境中的 myVar.
// 因此 inner 中定义 myVar 不会影响到 outer 中。
function inner() {
// 定义在这里,所以这是inner 环境下的myVar.
// 如果尝试访问outer 中定义相同名称,则获取的是outer 环境中的myVar.
// 因此inner 定义myVar不影响outer中。
if (true) {
console.log(myVar); // undefined,因为当前块没有myVar
myVar = "Inner"; // 创建我的 Inner 内嵌函数里的 local scoped 'my' variable
}
console.log(my); // 打印: Inner
}
}
块级 - Let & Const
对于block-level scope variables,如if/else statements, loops, switch cases等,这里有几个重要点:
Block-scoping: 与之前不同的是,不管是否在循环体内部,都能确保每次迭代都拥有独立副本。
Temporal Dead Zone (TDZ): 当你使用let或const进行解构赋值时,如果某个部分未指定初始值,它就会成为TDZ的一部分。如果尝试直接读取这样的未初始化属性,将返回undefined而不是抛出错误。但是,如果是在for循环头部直接使用let/const进行解构,则会导致运行时错误,因为这样做违反了暂时性死区(TDZ)规则。而且如果你的代码结构包含大量嵌套然后又不断缩进,你可能需要花费一些时间去理解哪些东西有效绑定到了哪里以及为什么有些东西根本不可触及(即使它们看起来应该是可触及的)。
No Re-declaration: 你不能重复宣告具有相同名字但是不同的scope上的block-scoped variables。(我觉得这句话有点模糊)
{
'use strict';
if (true) {
let x = 10; /* 变成了 block level */
console.log(x); /* 输出:10 */
{ /* 新起始另一种block level */
let y = 20;
console.log(y); /* 输出:20 */
} {/* 结束第二层 */}
console.log(y); /* TDZ -> ReferenceError */
}
console.log(x);
/* 输出:10 */
// 上面的例子展示了 how to use and understand the behavior of the three keyword types in JS:
// We have a global variable named "x"
// Then we create a block that declares two new variables with different names but same value ("y")
// After the block is closed and before we try to access it from outside its scope,
// trying to log or manipulate y will throw an error due to Temporal Dead Zone rules.
总结一下,我们看到每种方式都有自己独特的地方,而且各自适合用于解决不同的问题。选择何种方式取决于具体情况以及作者想要达到的效果。一旦熟悉这三个概念及其应用,你将发现自己的编码效率大幅提高,并且代码质量也提升得很快。