【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://blog.csdn.net/m0_69908381/article/details/139742129
出自【进步*于辰的博客】
关于编译与解释,详述可查阅博文《[Java]知识点》中的【编译与解释】一栏。
参考笔记二,P43.3、P46.1、P9.3。
文章目录
- 附言
- 1、什么是“变量提升?
- 2、var
- 3、let
- 4、解答
- 5、一种特殊情况
- 最后
附言
你在阅读本篇文章时,会看到一些名词,如:函数作用域,也就是由 var 声明的变量的作用域的名称,它是我根据我的理解自定义的。后来我了解到,JS中似乎并没有这个概念,对应的概念好像是“词法作用域”。
我暂未系统地学习JS,故无法详细地为你说明这个概念。当然,尽管我的用词可能不对,但就目前,这有助于我的学习理解。
如果你想进一步地学习这方面的知识,推荐一篇博文《JavaScript执行机制:变量提升、作用域链、词法作用域、块级作用域、闭包和this》(转发)。
1、什么是“变量提升?
“变量提升”是指在解释时,解释器先扫描整个JS脚本,将所有声明(包括变量和函数)移动到作用域顶端的机制,其本质就是声明与定义不同步的错觉。
var 与 let 具有相同的变量提升机制,故经变量提升后(“解释”后)的脚本相同。
PS:大家可能不明其意,往下看。
2、var
var 作用域的定义:
作用域的“上界”是变量声明处“往上”的第一个函数花括号(
{
)。
故也称为“函数作用域”。允许重复声明和定义,且“变量提升”时,函数优先级高于变量。
示例:
console.log(str)
console.log(append)
// console.log(append(str))// 报错
var str = '中'
var append = function(str) {
return str + '国'
}
console.log(str)
console.log(append(str))
经变量提升后:
var append;
var str;
console.log(str)-----------------------A
console.log(append)--------------------B
// console.log(append(str))------------C
str = '中'
append = function(str) {
return str + '国'
}
console.log(str)// 打印:中
console.log(append(str))// 打印:中国
输出结果:
变量提升机制将str
与append()
的声明移动到作用域顶部,故 A 和 B 的打印结果都是undefined
。
由于变量提升时,函数的优先级高于变量,所以append()
先于str
声明。但毕竟只是声明而非定义,因此在执行 C 时,append
只是一个未知变量,还不是函数,故报错。
3、let
let 作用域的定义:
作用域的“上界”是变量声明处“往上”的第一个花括号(
{
).
故也称为“块级作用域”。不允许重复声明和定义(同一作用域)。且与 var 不同的是,let 声明的变量在定义之前,存在
“暂时性死区”
\color{red}{“暂时性死区”}
“暂时性死区”,在定义前访问或赋值会报错。
(注:如let a
是声明,let a = 1
是定义。)
示例:(将上个示例稍作修改,var → let)
console.log(str)
console.log(append)
let str = '中'--------------------A
let append = function(str) {------B
return str + '国'
}
console.log(str)
console.log(append(str))
输出结果:
在 A、B 之前,就是相应变量的“暂时性死区”,故报错。
4、解答
1:为什么函数也会进行变量提升?
因为函数也是一种变量。
- JS中有一种
内部对象
\color{green}{内部对象}
内部对象是
Function
。 - 从函数声明
var xx = function()
可以看出。
2:如何解释“let 不允许重复声明和定义”?
我们先来看由 var 修饰的情况,示例:
var a = 1
var a = 2
经变量提升后:
var a
a = 1
a = 2
也就是:变量提升会将重复声明进行覆盖。
再来看 let 的情况。如果两个同名的变量都由 let 修饰,报错,这是 let 的特性。大家疑惑的多是这种情况:
var a = 1
let a = 2
先解答:也会报错。为什么?这涉及到一个细节:
var 的变量提升的优先级高于 let。
也就是说,经变量提升后:
var a
let a
a = 1
a = 2
这种情况 let 同样不允许,故报错。
稍作修改:
let a = 1
var a = 2
这种情况与上述完全相同,故也不允许。
5、一种特殊情况
在上文中,我们说到,这种情况不允许:
var a = 1
let a = 2
那么,请问下面这种情况能正常执行吗?
var a = 1
{----------------------A
let a = 2
}
要解决这个问题,就要研究 var 与 let 的作用域了,大家还记得我在上文中所述的它们的作用域的定义吗?结论:
第一个
a
的作用域是“全局”,而第二个a
的作用域是 A 处的代码块。
因此,两个a
的作用域不同,故不报错。
再给大家抛出一个问题:这样会报错吗?
let a = 1
{
var a = 2
}
PS:相信大家看到这里,已经对 var 和 let 有了足够的掌握,这个问题就交由大家思考了。
最后,为大家补充两个结论:
- var 是ES5的语法,let 是ES6的语法。
- 定义变量时可以不用 var 或 let 修饰(即直接
a = 1
),那么 var 与 let 的作用是什么?var 与 let 定义 / 决定了变量的作用域。因此,定义变量时如果不用 var 或 let 修饰,就不存在“变量提升”,则在定义前访问或赋值将直接报错。
最后
其实,在日常工作中,区分var与lei的实际作用并不大,我们更关注的是业务的梳理。因此,本篇文章旨在巩固JS基础。
本文完结。