,这是面试官最常问的问题转载本文请联系小鹿动漫学习编程公众号。本文沿着上一篇文章详细讲解的JavaScript执行上下文,继续深入作用域和作用域链。在上一篇文章中,《简而不单,单而不简!》主要分享了执行上下文的概念,作用域和闭包是基于执行上下文的概念来理解的。如果不了解执行上下文,不建议阅读本文。1.作用域如果说执行上下文是代码的执行环境,那么作用域就是执行环境中的一组执行规则。既然是规则,那么JavaScript引擎在执行代码的时候就必须遵守这套规则。同时,开发人员在编写代码时,也遵循这套规则。1.什么是作用域?我们先看一个例子:functionfoo(){varbar='xiaolu'}foo()console.log(bar)上面的运行结果很明显,控制台会报错barisnotdefined,我们通过这个小例子,你会发现在函数内部声明的变量在函数外部是不可访问的。这背后的原因是JavaScript作用域存在的结果。2.什么是词法环境?说到作用域,什么是作用域?让我们先认识一下我们的老朋友,词法环境。ECMAScript规范中对词法环境的描述如下:词法环境是一种规范类型,用于定义ECMAScript代码中标识符、变量值、函数值之间基于词法嵌套结构的关联。说白了,词法环境就是一套规范和规则,用来规定某些函数、变量等的可访问范围,我们也称词法环境为“词法作用域”。由于词法作用域是一组约定的规则,所以词法作用域的范围是开发人员在编写代码时确定的。当代码执行时,JavaScript引擎会根据这套规范,通过标识符名称查找对应的变量和函数。好吧,最后给它一个结论性的定义。作用域:作用域是一组约定的规范和规则,用于规定某些函数和变量的可访问性等。2.作用域链了解了作用域之后,我们再来看看作用域链。作用域链和作用域非常不同。下面我们从“执行栈层面”和“代码层面”来感受一下什么是作用域链。varname="xiaolu";functionfn(){console.log(name);functiongetName(){console.log(name);}getName();}fn();执行栈中的作用域链示意图:该图是上面代码的执行,在上面的示意图中,不同颜色块的缩进形成的可访问链就是我们所说的作用域链。上面的示意图虽然是抽象出来的,但是如果我们从代码层面去理解作用域链,它是如何实现的呢?正如上一篇文章所分享的,每当创建一个新的执行上下文时,都会创建一个“变量对象”,用于存储当前执行上下文中的变量和函数。(记住:这个变量对象很重要)如果我们把这些执行上下文的“变量对象”关联起来,就形成了一条链,我们把这条链的实现称为“作用域链”。上面代码的执行结果就是打印输出:varname="xiaolu";functionfn(){console.log(name);functiongetName(){console.log(name);}getName();}fn();当内部执行getName时,JavaScript引擎在getName的作用域中寻找变量名,如果发现没有变量名,就会沿着上图中的作用域链向上层寻找,而在fn作用域中没有找到name变量,然后继续按照函数域链向上层搜索,直到在全局作用域中找到变量name,然后输出name的值。
