JS 定义和使用变量

本文主要介绍了JavaScript中var、let、const定义变量的区别。var可重复定义,是全局作用域且有变量提升;let和const不能重复定义,是块级作用域且无变量提升,const还需初始值且值不可修改。此外,还通过案例展示了var特性导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

目录

1. var 定义变量

2. let 定义变量

3. const 定义变量

4. 使用 var 定义变量时有意思的案例


 

1. var 定义变量

 

(1) var 可以重复定义同一变量

<script>
  var a = '通过 var 第一次定义变量'
  console.log(a) // 结果:通过 var 第一次定义变量
  
  var a = '通过 var 重复定义变量'
  console.log(a) // 结果:通过 var 重复定义变量
</script>

 

(2) var 定义的变量是全局作用域, 会加到 window 对象的属性中

<script>
  var a = '通过 var 定义的变量'
  console.log(a) // 结果:通过 var 定义的变量
  console.log(window.a) // 结果:通过 var 定义的变量
  console.log(a === window.a) // 结果:true
</script>

 

(3) var 在 JS 引擎预解析时会进行变量提升, 所以 JS 编写时就算变量先使用后定义, 也可以正常运行, 只不过值是 undefined

   ① JS 引擎在预解析时, 会把变量声明部分提升至变量使用之前

   ② 只是变量声明的部分提升, 变量赋值的部分不动, 还在原来位置

<script>
  console.log(a) // 结果:undefined
  var a = '引擎对 JS 预解析时会进行变量提升'
  console.log(a) // 结果:引擎对 JS 预解析时会进行变量提升

  /*
    JS 引擎预编译后, 会变成类似这段代码

    var a;
    console.log(a)
    a = '引擎对 JS 预解析时会进行变量提升'
    console.log(a)
  */
</script>

 

2. let 定义变量

 

(1) 同一作用域内, let 不能重复定义同一变量

<script>
  let a = '定义变量'
  let a = '重复定义同一变量'
  // 运行报错: Uncaught SyntaxError: Identifier 'a' has already been declared
</script>

 

(2) let 定义的变量是块级作用域, 只能在当前代码块内使用

<script>
  function func(){
    let a = '块级作用域, 函数内可用'
    console.log(a)
  }
  func() // 结果: 块级作用域, 函数内可用
  console.log(a) // 运行报错:Uncaught ReferenceError: a is not defined
</script>

 

(3) let 定义的变量不会进行函数提升

<script>
  console.log(a)
  let a = '通过 let 定义的变量不会进行函数提升'
  // 运行报错: Uncaught ReferenceError: Cannot access 'a' before initialization
</script>

 

3. const 定义变量

 

(1) 同一作用域内, const 不能重复定义同一变量

<script>
  const a = '定义变量'
  const a = '重复定义同一变量'
  // 运行报错: Uncaught SyntaxError: Identifier 'a' has already been declared
</script>

 

(2) const 定义的变量是块级作用域, 只能在当前代码块内使用

<script>
  function func(){
    const a = '块级作用域, 函数内可用'
    console.log(a)
  }
  func() // 结果: 块级作用域, 函数内可用
  console.log(a) // 运行报错:Uncaught ReferenceError: a is not defined
</script>

 

(3) const 定义的变量不会进行函数提升

<script>
  console.log(a)
  const a = '通过 const 定义的变量不会进行函数提升'
  // 运行报错: Uncaught ReferenceError: Cannot access 'a' before initialization
</script>

 

(4) const 定义的变量必须给初始值, 并且定义后值不能修改(数组和对象类型变量只有修改指向的地址才算修改)

<script>
  // 未初始化
  const a // 运行报错: Uncaught SyntaxError: Missing initializer in const declaration
</script>
<script>
  // 对常量做修改
  const a = 1
  a = 2; // 运行报错: Uncaught TypeError: Assignment to constant variable.
</script>

 

4. 使用 var 定义变量时有意思的案例

 

(1) var 可重复定义变量和变量提升的特性导致的问题

<script>
  var a = 100;
  function func() {
    if (!a) {
      var a = 10
    }
    console.log(a) // 结果:10
  }
  func()
</script>

我们都知道 空串、 0、 nan、 null、 undefined 转换为布尔后为 false, 其余都为 true

也就是说 a=100 转换成布尔是 true, 那么 !a 就是 false, 理论上程序永远不会进入到逻辑分支里面

而是应该继续往下执行 console.log(a) , 并且输出应该是100, 但是实际结果确是 10

刚开始不理解, 后来自己想了想变量提升的伪代码瞬间懂了

 

变量提升伪代码:

<script>
  var a
  a = 100
  function func() {
    var a
    if (!a) { // 这时候 a 是 undefined, undefined 转成布尔是 false, 取反是 true, 所以条件成立
      a = 10
    }
    console.log(a)
  }
  func()
</script>

 

(2) var 全局作用域的特性导致的问题

<script>

  // 定义一个数组, 里面有三个空对象
  let objArray = [{}, {}, {}]

  // 遍历数组, 并在每个对象中加一个 method 方法
  for (var i = 0; i < objArray.length; i++) {

    objArray[i].method = function () {

      // 在方法中会用到变量 i
      console.log('这是第' + i + '个对象')
    }
  }

  // 遍历数组, 并执行 method 方法
  for (let i = 0; i < objArray.length; i++) {
    objArray[i].method()
  }

</script>

预想结果::这是第0个对象, 这是第1个对象, 这是第2个对象

实际结果: 这是第3个对象, 这是第3个对象, 这是第3个对象

 

现在将第七行的 var i = 0 改成 let i = 0 然后在执行

<script>

  // 定义一个数组, 里面有三个空对象
  let objArray = [{}, {}, {}]

  // 遍历数组, 并在每个对象中加一个 method 方法
  for (let i = 0; i < objArray.length; i++) {

    objArray[i].method = function () {

      // 在方法中会用到变量 i
      console.log('这是第' + i + '个对象')
    }
  }

  // 遍历数组, 并执行 method 方法
  for (let i = 0; i < objArray.length; i++) {
    objArray[i].method()
  }

</script>

预想结果::这是第0个对象, 这是第1个对象, 这是第2个对象

实际结果: 这是第0个对象, 这是第1个对象, 这是第2个对象

运行结果和预期的一样。

 

那么为什么使用 var 定义时, 就会出现非预期结果

其实出现这种情况的原因, 就是因为 var 定义的变量是全局作用域,  现在我把 debug 截图放上来,  一看便知

 

使用 let 的 debug 截图:

从上面截图可以看出来, 我观察的是每个对象中名为 method 的函数对象,  每个 method 函数对象中, 都分别保存了块级作用域变量 i

当执行 method 函数时, 就会找到并使用属于自己的块级作用域变量 i, 所以使用 let 执行结果和预期一样

 

使用 var 的 debug 截图:

 

我观察的仍然是每个对象中名为 method 的函数对象, 但是可以发现已经没有块级作用域变量了。

当 method 函数执行时, 需要用到变量 i ,但是因为没有块级作用域, 所以程序就会去全局作用域中找, 如下图

 

通过上面截图可以看到, 全局作用域中的 i 是 3, 所以使用 var 输出的结果就是 '这是第3个对象, 这是第3个对象, 这是第3个对象'

 

这里还有一个不好理解的地方, 就是 i 从 0 开始, 循环了3次,  应该是 0+1+1 = 2,  但是全局作用域中的 i 为什么是 3

这就考验对循环的掌握程度了,  循环体执行完 3 次后 i 确实是 2, 但是循环并不会因此退出, 而会执行 i++, 这个时候 i 就是3了,

然后再执行 i < objArray.length,  这时候条件已经不满足了, 才真正的退出循环, 但是因为已经执行过 i++ 了 所以 i 就变成了 3

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值