JS声明提升

写在前面

最近在读一本书《你不知道的JavaScript(上)》,刚好读到了提升这个章节。声明提升早在之前的公开课上就有所了解,不过那时候第一次接触还不是很清楚。当再次读到它的时候仿佛故友重逢一般,从中得到了更加深刻的认识,然后就做一下笔记(个人理解)。
然后这本书写的还是蛮好的,推荐大家有时间读一读,作者讲的比较风趣,而且通俗易懂。

声明提升

划一下重点

  • 声明提升在预编译阶段
  • 函数,变量的声明都会被提升,且函数会提到变量前面
  • 变量提升是不会超出当前作用域的
  • 被提升的只有声明哦,其他语句还是在原来的位置

变量声明提升

{
	a=5;
	var a;
	console.log(a); //5
}

如果按照从上到下理解的思路,a的声明在赋值后面,a会被重新赋值为undefined
但实际上并不是这样,在编译阶段a的声明语句会被提升,上面的代码其实和下面的代码是等价的

{
	var a;
	a=5;
	console.log(a); //5
}

注意:只有声明会被提升,其他语句是保留在原地的,看看下面的代码:

{
	console.log(a); //undefined
	var a = 2;
}

按照上面的声明提升,有人可能会认为是ReferenceError,但实际结果是undefined,为什么呢?
上面的代码和下面的代码是等价的:

{
	var a;
	console.log(a); //undefined
	a = 2;
}

就像之前说的,提升的只是变量的声明,var a = 2;其实是分两部分的

var a; //声明

a = 2; //赋值(执行阶段)

预编译四部曲

先了解下预编译,理解了预编译,可能对于后面的提升会有更好理解

  • 创建AO对象(执行期上下文)
  • 找到形参和变量声明,并将形参名和变量名作为AO对象的属性,默认值undefined
  • 实参与形参统一
  • 在函数体中找到函数声明,赋值

函数声明提升

函数声明提升和变量是类似的,不过函数声明会提到变量的声明之前,看下面的例子:

{
	var a = 2;
	console.log(a); //2
	function a() {
        a = 6;
    }
    a(); //TypeError
}

事实上,上面的代码是有问题的,a是没有办法作为函数执行的,上面的代码可以看作这样:

{
	//编译
	var a = undefined;
	a = function a(){
		a = 6;
	}
	//执行
	a = 2;
	console.log(a); //2
    a(); //TypeError
}

可以看到,编译阶段首先声明a,然后给a赋值为function(){},之后开始执行,但是在一开始aa=2被覆盖了,所以a不再是一个函数
下面是一个我曾经做过的练习,是一个综合的例子:

function fn(a){
	console.log(a);
	var a = 123;
	console.log(a);
	function a(){}
	console.log(a);
	console.log(b);
	var b = function(){}
	console.log(b);
}
fn(1);
  • 关于这个例子我要说明一点,在fn()内部 ,传参发生在最前面,这一点我还不晓得为啥子。

先不着急看结果,先一步步探讨代码编译、执行过程,上面的代码经过预编译之后:

var fn;
fn = function(a){
	//编译
	var a = undefined;
	var b = undefined;
	a = 1; //传进来的参数
	a = function a(){} //a函数声明提升
	
	//执行
	console.log(a);
	a = 123; 
	console.log(a);
	//function a(){}
	console.log(a);
	console.log(b);
	b = function(){} //这里是函数表达式,只会提升变量b的声明,赋值会保留
	console.log(b);
}
fn(1);

所以结果是:

function a(){}
123
123
undefined
function (){}

或许一开始接触可能会有些头皮发麻,其实只要能够清楚变量和函数提升的规则,理解起来就比较容易了!

发布了29 篇原创文章 · 获赞 8 · 访问量 4766

猜你喜欢

转载自blog.csdn.net/qq_40738077/article/details/101103777