JavaScript闭包+作用域+变量提升

阅读() @2018-10-29 18:16:09

JavaScript面试题(闭包、作用域、变量提升)

今天在微信里边看到2道JavaScript面试题,觉得挺有意思,因为它整合了JS中的闭包、作用域等问题,然后我稍加修改了一下,加入了变量提升的知识点,最后代码如下:

第一题:

var scope = 'global scope';
function a(){
	function b(){
		console.log(scope);
	}
	return b;
	var scope = 'local scope';
}
a()();//undefined

第二题:

var scope = 'global scope';
function a(){
	var scope = 'local scope';
	function b(){
		console.log(scope);
	}
	return b();
	
}
a();//local scope

首先来看看第一道题,这里边基本都涉及到了闭包、作用域和变量提升的问题,下面分几步来分析程序的执行过程:

第一步:因为函数a内部和外部都声明了变量scope,所以函数a内部的变量scope要提升到函数a的最顶部,也就是闭包b函数的上面,提升后的代码是:

var scope = 'global scope';
function a(){
	var scope;
	function b(){
		console.log(scope);
	}
	return b();
	scope = 'local scope';
}
a();

关于变量提升的详细讲解,可以参考《关于javascript执行顺序、变量提升、作用域的问题》。

第二步:接下来程序先执行定义外部的全局变量scope,定义函数a;

第三步:所有的变量都声明完成之后,开始执行赋值操作,将‘global scope’赋值给全局变量scope,开始执行函数a;

第四步:函数a的执行结果就是函数b的执行结果,因为b是一个闭包(关于闭包的概念,可以参考《我对javascript中【闭包】的理解》),所以函数b内部打印的是scope变量,所以会首先在b内部查找有无scope的值,发现没有,然后在向上一层查找,在a函数内部有scope的定义,但是程序执行到这步的之后,scope=‘local scope’还没有执行到,所以没有进行赋值,因此a内部的局部变量此时的值是“空值”undefined;

第五步:最后打印出的结果就是undefined。

有的同学会说,既然是“空值”,那为什么不是null,而是undefined呢?对于这个问题,可以参考《JavaScript中null和undefined的区别》。

搞明白第一道题的执行过程,看第二道题就不难了,因为第二道题里边没有变量提升,所以最后打印出的结果就是“local scope”。

另外,如果大家仔细观察的话,发现第一道题的执行是a()(),第二道题的执行时a(),一个括号和两个括号,这主要取决于闭包是在何时执行,但是最后的结果是一样的,因为对于大多数函数来说,函数执行完成之后,函数内部的局部变量就会自动销毁,释放内存,但是闭包b的执行依赖于函数a,因此函数a会永远存在在内存中。

永远保存在内存中会不会导致内存泄露的问题呢?肯定的说,对于IE8以上的浏览器,基本不存在内存泄露的问题,可以参考《JavaScript对象循环引用与闭包导致的内存泄漏及其解决方案》。

微信二维码