JS词法分析,那些有逼格的面试题都会考

一、概念

大家都知道JS是一门解释性的语言,不存在类似C、C++的编译、链接过程。但是JS在解释的时候却是按照一定规则来执行的,这个规则就是今天我要给大家说的词法分析。我暂且把这个过程称为执行前的预处理吧。

二、举个装逼的例子

请在半分钟内说出,下面代码输出什么?

function a(b){
    console.log(b);
    var b = 22;
    console.log(b);
    function b(){
        console.log(b);
    }
    console.log(b);
}

a(11);

怎么样?你能回答出来吗?如果还不能,那么接着往下看吧。

三、词法分析过程

你随便百度一下“JS词法分析”,大多数的文章都有这么一个过程,如下:

1、分析函数参数

2、分析函数内的变量声明

3、分析函数内的函数声明

4、先分析,再执行

第四条是我加的,这个过程,请一定牢记,实在记不住就写在自己的小本本上吧。

在函数运行前,会对应生成一个函数的虚拟活动对象Active Object(大家都这么叫),它记录了函数内部所有的参数、所有的变量,简称AO。

在函数最开始,因为没有任何参数和变量,此时AO是一个空对象,AO={}。

结合我们那个例子来分析

1、首先分析参数

function a(b){
// --> 由于参数b=11,此时AO = {b:11}
    console.log(b);
}
a(11);

我们先把示例中部分代码去掉,如果直接打印,那么肯定是11了。

2、再分析变量声明

分析变量声明的时候需要注意,在函数内部使用var声明的变量会隐藏函数外部的变量!

function a(b){
    console.log(b);
    var b = 22;
    console.log(b);
}
a(11);

然后,我们再加上变量声明的代码,这个时候分析之后的执行过程,可以改写为如下:

function a(b){
//  --> 最开始的时候OA为空,类似于下面这句定义b但不初始化
    var b;
// --> 由于参数b=11,此时AO = {b:11}    
    console.log(b);
    b = 22;
// --> 由于b重新赋值为22,此时AO = {b:22}        
    console.log(b);
}
a(11);

整个执行过程也就清晰了。

3、最后分析函数声明

函数声明有一点需要特别注意,即,用function显示定义的函数声明,会自动提升到作用域的开头!

我们再分析下完整的例子

function a(b){
// --> 由于参数b=11,此时AO = {b:11}    
// --> 由于显示声明的函数提前,此时AO = { b:function b(){ ...} }    
    console.log(b);   
    var b = 22;
// --> 由于b重新赋值为22,此时AO = {b:22} 
    console.log(b);
    function b(){
        console.log(b);
    }
// --> 此时b并没有改变,AO 还是为{b:22}     
    console.log(b);
}

a(11);

上面代码的注释中,请看箭头部分的注释,详细分析过程已经标示出来了。最后的执行过程,应该输出什么,我相信你应该能在30s内答出来了。

4、先分析,再执行

上面的三步词法分析之后,函数执行的时候只需要关注OA上的变量即可,不用关心哪里定义了函数,哪里定义了变量,因为都在OA上了。

另外,如果在当前OA上没找到对应的变量或者函数,会对应从上一层作用域中去寻找,直至最外层的全局OA为止。

最后、多看多练才能提升

下面,是我在网上搜集的词法分析的装逼题目,方便大家练习。各位看官可以用上面这个步骤来分析分析,一般来说30s就能知道答案了。

请注意:下面有的题目就是因为词法分析不到位,是会报错的!

function t(age) {
	var age;
	console.log(age);
	function age() {
		console.log(age);
	}
	age();
	console.log(age);
}
t(5);
function t(age) {
	var age;
	console.log(age);
	age = "99";
	console.log(age);
	function age() {
		console.log(age);
	}
	age();
	console.log(age);
}
t(5);
function t(age) {
	console.log(age);
	// 这里有个坑
	var age=function age () { 
		console.log(age);
	}
	age();
	console.log(age);
}
t(5);
x();
var x = function(){
    console.log(1);
}

function x(){
   console.log(2);
}
x();
var i=10;
function a() {
    console.log(i);  
    var i = 2; // 提示:内部定义会隐藏外部变量
    console.log(i);  
};
a();

上面这些题目,我随便搜的,多练习练习拿去装逼吧。

(本文完)



打赏作者

发表评论

电子邮件地址不会被公开。 必填项已用*标注