当前位置: 首页 > 科技观察

面试官爱问的作用域和作用域链

时间:2023-03-21 14:06:54 科技观察

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