论JavaScript变量提升与作用域
2023 / 3 / 1 By: Awayer(阿为)
一、变量提升部分
1.什么是变量提升
在JavaScript里,用var定义变量时,会存在变量提升的情况,例如:
console.log(a);
var a = 114514; //输出结果为:undefined
经过变量提升后,系统会把代码整理成以下形式:
var a;
console.log(a); // undefined
a = 114514;
但是,如果我用let来声明变量,那么就会报错:
console.log(a);
let a = 114514; //a未初始化
原因:js中,var存在变量提升,但是let不存在。
但是其实上,let定义的变量也有提升,只不过提升的只是创建,初始化和赋值并不会提升。var的提升会在创建时初始化变量为undefined
2.变量提升的几种情况
(1)变量在全局里被提升
console.log(a);
var a = 114514; //输出结果为:undefined
(2)变量在函数里被提升
function fn() {
console.log(a); // undefined
a = 114514;
console.log(a); // 114514
}
在函数里用var定义变量也会存在变量提升
(3)函数是一等公民
var a = 114514;
function fn(){
console.log(a);
function a(){}
}
fn(); // function a(){}
上述代码等同于:
function fn() {
function a(){}
console.log(a);
}
var a;
a = 114514;
fn(); //function a(){}
上述代码中,发生了2次函数声明提升,在全局中将fn函数提升到全局的最前面,之后在fn函数中又将a函数提升到fn函数里的最前面,所以打印出来的a 是函数。
(4)变量型声明的提升
现在我们用一个变量来接收函数:
fn() //Uncaught TypeError: fn is not a function
var fn = function () {
console.log(1)
}
原因:上述代码中,变量fn被提升到全局的最前面,此时变量fn还未被赋值为函数,所以在下一条语句调用函数时会报错。
二、作用域部分
*在js中存在三种作用域:全局作用域、函数作用域、块级作用域
1.全局作用域
不在大括号里声明的变量,就是全局变量,他可以在任何地方被访问到,例如:
var str = "qwq";
function fn(){
console.log(str);
}
fn(); // qwq
2.函数作用域
函数作用域也叫局部作用域,在函数内声明的变量只能在函数内被访问。
function fn(){
var str = "qwq";
console.log(str);
}
fn(); //qwq
console.log(str); // str is not defined
3.块级作用域
ES6引入了let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。
例一
if(true){
let a = 1;
}
console.log(a); // a is not defined
例二
{
let str = 'Hello World!';
var a = 'English';
console.log(str); //Hello World!
}
console.log(a); //English
console.log(str); //str is not defined
例二中在大括号内使用var声明的变量可以在大括号外被访问,而let不能。
4.作用域链
作用域链就是当JS在用到一个变量时他会在当前作用域寻找,如果在当前作用域中没找到,他会去上一个作用域找
let str = 'awayer';
let num = 114514;
function a() {
let a = 'qwq';
console.log(a); //qwq
console.log(str); //awayer 当前作用域中找不到str,于是到上一层作用域中找到了str
num = 42;
console.log(num); // 42
}
a();
三、例题部分
1.
var n = 10;
function fn(n) {
console.log(n);
var n = 20;
console.log(n);
function n() { };
console.log(n);
};
fn(n);
console.log(n);
// fn(){}
// 20
// 20
// 10
2.
console.log(a, b);
var a = 12, b = 'awayer';
function foo(){
console.log(a, b);
var a = b = 13;
console.log(a, b);
}
foo();
console.log(a, b);
// undefined undefined
// undefined awayer
// 13 13
// 12 13
3.
console.log(a);
var a=1;
function a(){
console.log(1);
}
// function a(){...}
4.
let a = 0, b = 0;
function fn(a) {
fn = function fn2(b) {
console.log(a, b)
console.log(++a+b)
}
console.log('a', a++)
}
fn(1); // a, 1
fn(2); // 2, 2 5
5.
console.log(a); // function(){console.log(2)}
a(); // 2
var a;
a=function(){console.log(1);}
a(); // 1
function a(){console.log(2);}
a=3;
console.log(a); // 3