变量提升
先说三句总结性的话:
let 的创建过程被提升了, 但是初始化没有提升
var 的创建和初始化都被提升了
function 的创建初始化和赋值都被提升了
所以, 我们要注意, 这三种变量提升, 含义是不同的
变量提升的规律
在进入一个执行上下文后, 先把 var 和 function 声明的变量前置, 再去顺序执行代码
PS: 作用域分为全局作用域和函数作用域, 用 var 声明的变量, 只在自己所在的所用域有效
我们举例来看看下面的代码
代码 1:
- console.log(fn);
- var fn = 1;
- function fn() {
- }
- console.log(fn);
相当于:
- var fn = undefined;
- function fn() {
- }
- console.log(fn);
- fn = 1;
- console.log(fn);
打印结果:
代码 2:
- console.log(i);
- for (var i = 0; i <3; i++) {
- console.log(i)
- }
相当于:
- var i = undefined;
- console.log(i);
- for (i = 0; i < 3; i++) {
- console.log(i);
- }
打印结果:
代码 3:
- var a = 1;
- function fn() {
- a = 2;
- console.log(a)
- var a = 3;
- console.log(a)
- }
- fn();
- console.log(a);
相当于:
- var a = undefined;
- function fn() {
- var a
- a = 2
- console.log(a)
- a = 3
- console.log(a)
- };
- a = 1;
- fn();
- console.log(a);
打印结果:
声明时的重名问题
假设 a 被声明为变量, 紧接着 a 又被声明为函数, 原则是: 声明会被覆盖 (先来后到, 就近原则)
PS:
如果 a 已经有值, 再用 var 声明是无效的
如果 a 已经有值, 紧接着又被赋值, 则赋值会被覆盖
举例 1:
- var fn; //fn 被声明为变量
- function fn() {// fn 被声明为 function, 就近原则
- }
- console.log(fn); // 打印结果: function fn(){}
举例 2:
- function fn() {} //fn 被声明为 function, 且此时 fn 已经被赋值, 这个值就是 function 的对象
- var fn; //fn 已经在上一行被声明且已经有值, 再 var 无效, 并不会重置为 undefined
- console.log(fn) // 打印结果: function fn(){}
既然再 var 无效, 但是再 function, 是有效的:
- function fn() {} //fn 被声明为 function, 且此时 fn 已经有值, 这个值就是 function 的对象
- function fn() { // 此时 fn 被重复赋值, 会覆盖上一行的值
- console.log('smyhvae');
- }
- console.log(fn)
打印结果:
函数作用域中的变量提升 (两点提醒)
提醒 1:
在函数作用域也有声明提前的特性:
使用 var 关键字声明的变量, 是在函数作用域内有效, 而且会在函数中所有的代码执行之前被声明
函数声明也会在函数中所有的代码执行之前执行
因此, 在函数中, 没有 var 声明的变量都会成为全局变量, 而且并不会提前声明
举例 1:
- var a = 1;
- function foo() {
- console.log(a);
- a = 2; // 此处的 a 相当于 window.a
- }
- foo();
- console.log(a); // 打印结果是 2
上方代码中, foo() 的打印结果是 1 如果去掉第一行代码, 打印结果是
Uncaught ReferenceError: a is not defined
提醒 2: 定义形参就相当于在函数作用域中声明了变量
- function fun6(e) {
- console.log(e);
- }
- fun6(); // 打印结果为 undefined
- fun6(123);// 打印结果为 123
其他题目
- var a = 1;
- if (a> 0) {
- console.log(a);
- var a = 2;
- }
- console.log(a);
打印结果:
1 2
上方代码中, 不存在块级作用域的概念 if 语句中用 var 定义的变量, 仍然是全局变量
顺便延伸一下, 用 let 定义的变量, 是在块级作用域内有效
来源: https://www.cnblogs.com/smyhvae/p/8619437.html