论JavaScript变量提升与作用域

95 阅读3分钟

论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引入了letconst关键字,和var关键字不同,在大括号中使用letconst声明的变量存在于块级作用域中。

例一

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