详解变量声明加 var 和不加 var 的区别

在全局作用域中声明变量加 var 关键字和不加 var ,js 引擎都会将这个变量声明为全局变量,在实际代码运行时,两种声明方式的变量的行为也几乎是一致的。但是在全局作用域下是否声明一个变量的时候加 var 和不加 var,js 引擎具体执行了哪些操作呢,其效果又是否完全一致?

首先我们看在一个函数体内(局部作用域)声明变量,如下:

复制代码
// 变量声明不加 var
function foo (a) {
  console.log(a + b) // b is not defined
  b = a
}

foo(2)
复制代码

【分析】执行 foo(2) 的时候,我们具体看 foo 函数,首先打印了 a + b 的值,然后声明了一个 b 变量(没有使用var关键字),并将传入的 a 赋值给 b,因为 js 引擎按照代码顺序编译和执行代码,因此在打印 a + b 的时候,在任何作用域中都是无法找到 b 变量的。

在执行 foo(2) 表达式的时候 js 引擎具体的的操作过程如下:

  1. 在当前作用域中查找名为 foo 的函数(RHS)
  2. 进入 foo函数体,首先 JS 引擎在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),从而确定变量的作用域。因此第一步搜集变量,发现在函数作用域中这里只有作为参数的局部变量 a,提升到作用域顶部
  3. 将 2 赋值给参数变量 a(a = 2, LHS)
  4. 查找 console 对象(RHS),发现是内置函数,在 console 对象下查找 log 函数(RHS)
  5. 在当前作用域中查找变量 a,并获取 a 的值为(a = 2, RHS)
  6. 在当前作用域中查找变量 b,未找到该变量
  7. 将 a 和 b 的查找结果传入 console.log() 函数,打印结果( b 未定义,抛出错误: b is not defined)
  8. 继续执行 b = a。首先获取变量 a 的值(a = 2, LHS), 然后在当前作用域中查找变量 b(RHS),未找到,到上一层作用域(全局作用域)中查找(RHS),未找到,
  9. 在全局作用作用域中创建一个名称为 b 的变量,并将其返回给引擎(注意:严格模式下禁止自动或隐式地创建全局变量)
  10. 将 a 的值(2)赋值给全局变量 b( b = a, LHS)

再看第二个例子

复制代码
// 变量声明加 var
function foo (a) {
  console.log(b) // undefined
  console.log(a + b) // NaN
  var b = a
}

foo(2)
复制代码

【分析】执行 foo(2) 的时候,我们看 js 引擎具体做了哪些操作?

  1. 在当前作用域中查找名为 foo 的函数(RHS)
  2. 进入 foo 函数体,搜集变量,发现声明了局部变量 a 和 b,因此将 a 和 b 提升到函数作用域的顶部(此时 b 的值为 undefined)
  3. 参数赋值,将 2 赋值给变量 a(a = 2, LHS)
  4. 查找 console 对象(RHS),发现是内置函数,在 console 对象下查找 log 函数(RHS)
  5. 在当前作用域中查找变量 b(RHS),发现已经声明,但是值为 undefined ,传给log()函数,执行打印,输出结果(b is not defined)
  6. 重复第4步 RHS 查找 console.log() 函数,查找变量 a 的值(a = 2, RHS);查找变量b的值(b = undefined, RHS),将 a 和 b 的值传入 console.log(),执行运算,输出结果(2 + undefined,结果 NaN)

通过上述在函数体内声明变量的资历,已经可以看出来 js 引擎在处理这两种情况的区别,在全局作用域中的也是如此,而且理解起来更为简单。

看两个例子:

console.log(a) // undefined
a = 3

声明变量 a 的时候没有加 var,因此 js 引擎默认将变量 a 声明为全局变量(值为 undefined)并提升到作用域顶部(为什么在console.log() 中可以访问到 a),但是此时的赋值操作需要等到 console.log() 方法执行完之后才会执行,因此在 console.log(a) 打印的结果会是 undefined

console.log(a) // undefined
var a = 3

这里的输出结果仍旧是 undefined,但是和上面的例子不同的是, js 引擎并没有主动的去创建变量 a,而是直接将变量 a 搜集到全局变量的集合中,并将 a 提升到作用域顶部。

【本文由“java员工”发布,2017年10月22日】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值