之所以说是两道“变态”的面试题,因为这两类JavaScript代码在运行时不按常理出牌,究其根本原因就是:在运行的过程中,会多出一个私有的块级上下文,从而导致运行结果与常规不同。下面我们就来具体分析一下;
- 变态一
{
function foo(){
}
foo = 1
}
console.log(foo);
上面这段代码在老版本浏览器(IE10以下)和在新版本浏览器中运行出来的结果是完全不同。先不管最终运行结果是什么,我们先来分析一下在新老版本中的运行步骤
- 老版本浏览器:
- 首先还是开辟一块栈内存(ECStack)供代码执行
- 接下来形成一个全局上下文EC(G),然后变量提升,声明并定义一个函数foo
- 代码执行,因为老版本浏览器不存在块级上下文,所以这里代码块中的代码也是直接在全局上下文中执行。第一句代码在变量提升时已经处理过,直接跳过执行第二句代码“foo=1”,这里foo由函数被变更为值1
- 执行console.log(foo) 输出值1
- 新版本浏览器:
- 第一步也是先开辟栈内存(ECStack)供代码执行
- 第二步形成全局上下文EC(G),然后变量提升,这里就开始出现不同了。这里有这么一套运行机制:
- 在全局上下文中,除了函数/对象以外的大括号,如果在其它大括号(循环体、判断体、代码块等)中出现let/const/function,则会再单独形成一个块级私有上下文
- 如果在除函数/对象以外的其它大括号中出现function时,则变量提升只是声明不再定义
- 第三步变量提升:依照上面的第二条规则,代码块中出现了function,所以在全局上下文中只声明一个foo,并不定义
- 第四步代码执行:依照第二步第一条规则,代码块中出现了function,所以这里会单独再形成