一、解析过程
js运行前会有编译解析过程,有些错误会在编译过程中被发现。
<body>
<script>
var web = 'yooo';
console.log(web);
var class = 'alison';
</script>
</body>
二、变量提升
<body>
<script>
console.log(web);
var web = 'yooo';
</script>
</body>
为什么不会报错?
因为在解析阶段进行了变量提升,变量初始化=定义+赋值,浏览器将定义部分提升到了console.log之上。即变量可以在定义之前使用,值为undefined。上面代码相当于如下。
<body>
<script>
var web;
console.log(web);
web = 'yooo';
</script>
</body>
再举一个函数的例子
<body>
<script>
function hd() {
if (false) {
var web = 'yooo';
}
console.log(web);
}
hd();
</script>
</body>
依旧不会报错,道理同上,上面代码相当于如下。
<body>
<script>
function hd() {
var web;
if (false) {
web = 'yooo';
}
console.log(web);
}
hd();
</script>
</body>
但这是js一个不好的习惯,会包容很多缺点,导致实际与预期不符。
如何克服?使用let/const初始化变量
三、let&const暂时性死区TDZ
将var声明改成let/const后,变量提升消失,控制台报错。
<body>
<script>
console.log(web);
let web = 'yooo';
</script>
</body>
<body>
<script>
console.log(web);
const web = 'yooo';
</script>
</body>
为什么会报错?
因为在let/const声明变量之前使用该变量,会产生一个暂时性死区TDZ,必须在声明之后才能使用。
再举一个函数的例子
<body>
<script>
let web = 'yooo';
function func() {
console.log(web);
let web = 'yoo';
}
func();
</script>
</body>
为什么报错?
当函数体内未定义变量web,则去函数体外找;若在函数体内定义了web变量,则必须在执行语句前定义。
即因为在块级作用域内有let/const定义了局部变量web,该块级作用域形成封闭,之前let声明的全局变量web就不起作用了。
再举一个函数参数的例子
<body>
<script>
function run(a = b, b = 3) { }
run();
</script>
</body>
为什么报错?
因为给a赋值b时,b未进行变量初始化,因此产生了一个临时性死区TDZ
如下则不会报错。
<body>
<script>
function run(a = 3, b = a) { }
run();
</script>
</body>