【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://blog.csdn.net/m0_69908381/article/details/139742129
出自【进步*于辰的博客】
关于编译与解释,详述可查阅博文《[Java]知识点》中的【编译与解释】一栏。
参考笔记二,P43.3、P46.1、P9.3。
文章目录
- 附言
- 1、介绍
- 2、解答
- 3、一种特殊情况
- 最后
附言
你在阅读本篇文章时,会看到一些名词,如:函数作用域,也就是由 var 声明的变量的作用域的名称,它是我根据我的理解自定义的。后来我了解到,JS中似乎并没有这个概念,对应的概念好像是“词法作用域”。
我暂未系统地学习JS,故无法详细地为你说明这个概念。当然,尽管我的用词可能不对,但就目前,这有助于我的学习理解。
如果你想进一步地学习这方面的知识,推荐一篇博文《JavaScript执行机制:变量提升、作用域链、词法作用域、块级作用域、闭包和this》(转发)。
1、介绍
什么是“变量提升?
“变量提升”是指在解释时,解释器先扫描整个JS脚本,将所有声明(包括变量和函数)移动到作用域顶端的机制,其本质就是声明与定义不同步的错觉。
var 与 let 具有相同的变量提升机制,故经变量提升后(“解释”后)的脚本相同。
PS:大家可能不明其意,往下看。
先说说两种修饰符声明变量的作用域的定义:
var
:作用域的“上界”是变量声明处“往上”的第一个函数花括号({
),故也称为“函数作用域”。var 允许重复声明和定义。let
:作用域的“上界”是变量声明处“往上”的第一个花括号({
).,故也称为“块级作用域”。let 不允许重复声明和定义(同一作用域)。
let 与 var 不同的是,let 声明的变量在定义之前,存在“暂时性死区”,
示例:
console.log(str)
let str = 1
输出结果:
因为示例代码经“变量提升”后:
let str
console.log(str)
str = 1
这就是“暂时性死区”,在定义前访问或赋值会报错。如:let str
是声明,let str = 1
是定义。
2、解答
1:如何理解“函数的变量提升优先于变量?”(PS:一些资料中可能会这样阐述)
事实上,之前由于我的JS功底不够扎实,也误解了这句话,以为是这样:
console.log(b)
var a = 1
var b = function() {return 2
}
经变量提升后:
var b
var a
console.log(b);// undefined
a = 1
b = function() {return 2
}
如果真的如我之前这般理解,无意义,并且也理解错误。
那么,“函数的变量提升优先于变量”这句话到底是什么意思?我从博文《JavaScript执行前的秘书——预编译》(转发)中取经得知,如下:
console.log(b)
var a = 1
function b() {return 2
}
经变量提升后:
function b() {return 2
}
var a
console.log(b);// [Function: b]
a = 1
所以,我之前是把var b = 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
这种情况与上述完全相同,故也不允许。
3、一种特殊情况
在上文中,我们说到,这种情况不允许:
var a = 1
let a = 2
那么,请问下面这种情况能正常执行吗?
var a = 1
{----------------------Alet 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 修饰,就不存在“变量提升”,则在定义前访问或赋值将直接报错。
还有,const
也会“变量提升”,如let
一般,具有块级作用域。
本文完结。