摘要:我们再来看一下第一段代码小红小黑脚本出错脚本出错在这段代码中变量与函数,都拥有局部作用域。作用域链的最前端,始终都是当前执行代码所在的作用域的变量对象。
全局作用域个人博客原址
无论什么语言中,作用域都是一个十分重要的概念,在JavaScript中也不例外,作用域定义了变量或者函数有权访问的范围,决定了它们各自的行为。要理解JavaScript中的作用域首先就要知道:在let出现之前,JS中变量的作用域只有两种:全局作用域和局部作用域。(本文也只讨论这两种作用域)
全局作用域是最外围的一个执行环境,可以在代码的任何地方访问到。在浏览器中,我们的全局作用域就是window。因此在浏览器中,所有的全局变量和函数都是作为window对象的属性和方法创建的。
下面就来看看全局作用域的创建方式:
全局变量与全局函数
var name = "小红"; function doSomething(){ var anotherName = "小黑"; function showName(){ console.info(name) console.info(anotherName) } showName(); } console.info(name);//小红 console.info(anotherName);//【脚本出错】 doSomething();//小红---小黑 showName();//【脚本出错】
通过代码可以很清楚的看出来,我在前面所说的 作用域定义了变量或者函数有权访问的范围 ,在这里我们定义了一个全局的变量name与全局函数doSomething(),他可以在任何地方被直接访问。但是我们又在函数内部创建了变量anotherName与函数showName(),通过代码中的调用情况可以发现,我们在外部调用它时提示【脚本出错】,因为他们处于局部作用域内(稍后讲),而 外部环境不能访问内部环境的任何变量与函数。这就涉及到了作用域的概念(稍后讲)
未声明直接定义的变量
function showName() { var fullName = "小红"; anotherName = "小黑"; console.info(fullName) } showName();//小红 console.info(anotherName);//小黑 console.info(fullName);//【脚本出错】
在这样的情况下,变量anotherName拥有全局作用域,而fullName在函数外部无法访问到。(注:在高程中明确说明,不声明而直接初始化变量是错误做法,应该避免这样的情况严格模式下,初始化未声明的变量将报错)
所有window对象上的属性都具有全局作用
这个实际上在上面已经提到了:所有的全局变量和函数都是作为window对象的属性和方法创建的。,自然window对象它本身所具有的属性和方法,同样是处于全局作用域,例如:window.location,window.name等等。
局部作用域其实在上面的代码中,为了展示全局作用域的效果,我们就已经创造了局部作用域。局部作用域和全局作用域正好相反,局部作用域一般只在固定的代码片段内可访问到,最常见的就是函数内部,所以在很多地方就会有人把它称为函数作用域。(记住let之前无块级作用域)。我们再来看一下第一段代码:
var name = "小红"; function doSomething(){ var anotherName = "小黑"; function showName(){ console.info(name) console.info(anotherName) } showName(); } console.info(anotherName);//【脚本出错】 showName();//【脚本出错】
在这段代码中变量 anotherName,与函数 showName(),都拥有局部作用域。因此它不能被外部所访问,那么问题就来了,为什么全局变量他就能在局部作用域内被访问到呢?这就是 JavaScript 中的作用域链概念!
作用域链在JS中:”一切皆是对象, 函数也是”。
在 JavaScript 中,每个函数都有着自己的作用域,在每次调用一个函数的时候 ,就会进入一个函数内的作用域,而当函数执行返回以后,就返回调用前的作用域。
当代码在一个作用域内执行时,就会根据其上下文创建一个作用域链,该作用域链的用途就是控制当前作用域对于内所有的变量与函数的有序访问。作用域链的最前端,始终都是当前执行代码所在的作用域的变量对象。
var name = "小红"; function changeName(){ if(name ==="小红"){ name="小黑"; }else{ name ="小红"; } } changeName(); console.info("新名字:"+name);//小黑
在这个例子中,changName()被定义在全局作用域下,他的作用域链包含着包含两个对象:1.它本身的变量对象(函数都会包含arguments对象),2.全局环境对象。之所以能在函数内部访问到变量name,就是因为在它的作用域中,能找到它。(JS的标识符解析,是沿着作用域链一级一级的查找搜索的过程,从作用域链的最前端开始直到全局环境,最终没有查找到时将报错。)我们再回过头来稍微改一下第一段代码:并且看看他们能访问到那些变量:
var name = "小红"; function doSomething(){ var anotherName = "小黑"; function showName(){ var author ="三省吾身丶丶"; console.info(name) console.info(anotherName) // 在这里可以访问到 name 、anotherName 、author } showName(); // 在这里可以访问到 name anotherName ,不能访问到 author } doSomething(); // 在这里只能访问到 name
要想理解这种作用域其实也很简单,作用域就像是一架 每一个台阶都是相对封闭(同级),并且只能上不能下的梯子,在越底层的台阶上,它能走的步数越多(作用域链越长)。为了找到它想要的东西,就开始爬台阶,每爬一步台阶,都能看到这一级台阶上有什么东西,直到最顶上的那一阶。(找到了就带回去一起玩耍,玩完了之后还得换回去,要是最后都没找到就掉下去摔死了)
坑与示例解析在了解坑之前,其实只要记住权威指南里面的一句话,就可以躲过很多这方面的坑了,那就是:JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里
下面就来看看这一个例子:
var name = "小红"; function showName() { console.info(name); } function show() { var name = "小黑"; showName(); } show();
结果会是什么呢?
小红
如果你记住并且理解了上面的话,那么应该可以得到这个结果。用作用域链的角度解析:执行show()函数时,进入function show(){}的作用域内,然后执行showName()函数,再进入到function showName(){}的作用域内,要输出name,就在当前作用域找,但是找不到,然后就向上爬一层,在全局环境中找到了var name = "小红";,所以show()就输出了小红。
再来看一个这个例子的改动版本
var name = "小红"; function show() { var name = "小黑"; function showName() { console.info(name); } showName(); } show();
结果是:小黑
解析:执行show()函数时,进入function show(){}的作用域内,然后执行showName()函数,再进入到function showName(){}的作用域内,要输出name,就在当前作用域找,发现本身找不到,就向上爬一层到了show()里面,发现已经找到了var name = "小黑";,那么就停止查找,输出了小黑
。
先到这,不知道有没有对作用域有了更多的了解呢?感觉有些地方还了解的不够透彻,希望在开发项目的过程中能有更深的理解。
如果有错误之处,请指正。谢谢!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/79954.html
摘要:关于作用域实现的描述任何执行上下文时刻的作用域,都是由作用域链来实现的。在一个函数被定义的时候,会将它此时的作用域链链接到这个函数对象的属性。参考资料鸟哥作用域原理理解作用域和作用域链阮一峰老师微博上的关于作用域的一道题 javascript作用域原理学习 在每次调用一个函数的时候,就会进入一个函数内的作用域,当从函数返回 以后,就会返回调用前的作用域。 ECMA262关于作...
摘要:函数的作用域也可被分为全局作用域和局部作用域函数作用域被定义在指定函数内部的函数被称为局部函数或内部函数。局部变量在函数内部声明的变量被成为局部变量,它只能在函数的内部进行访问。 作用域 概述 变量和函数都具有作用域 作用域就是变量和函数的可被访问的范围 控制着变量和函数的可见性和生命周期。变量的作用域可被分为全局作用域和局部作用域(函数作用域) 如果变量是被定义在全局作用域的话 在J...
摘要:闭包是怎么通过作用域链霸占更多内存的本文是作者学习高级程序设计第一小节的一点个人理解,详细教程请参考原教材。函数执行过程创建了一个函数的活动对象,作用域链的最前端指向这个对象。函数执行完毕返回值后执行环境作用域链和活动对象一并销毁。 JavaScript 闭包是怎么通过作用域链霸占更多内存的? 本文是作者学习《JavaScript 高级程序设计》7.2第一小节的一点个人理解,详细教程请...
摘要:一前言这个周末,注意力都在学习基础知识上面,刚好看到了闭包这个神圣的东西,所以打算把这两天学到的总结下来,算是巩固自己所学。因此要注意闭包的使用,否则会导致性能问题。五总结闭包的作用能够读取其他函数内部变量。 # 一、前言 这个周末,注意力都在学习基础Js知识上面,刚好看到了闭包这个神圣的东西,所以打算把这两天学到的总结下来,算是巩固自己所学。也可能有些不正确的地方,也请大家看到了,麻...
摘要:全局执行环境的变量对象始终是作用域链中的最后一个变量对象。综上,每个函数对应一个执行环境,每个执行环境对应一个变量对象,而多个变量对象构成了作用域链,如果当前执行环境是函数,那么其活动对象在作用域链的前端。 1.几个概念 先说几个概念:函数、执行环境、变量对象、作用域链、活动对象。这几个东东之间有什么关系呢,往下看~ 函数 函数大家都知道,我想说的是,js中,在函数内部有两个特殊...
阅读 2464·2021-09-29 09:34
阅读 3300·2021-09-23 11:21
阅读 2493·2021-09-06 15:00
阅读 1122·2019-08-30 15:44
阅读 2023·2019-08-29 17:23
阅读 2996·2019-08-29 16:44
阅读 3051·2019-08-29 13:13
阅读 1931·2019-08-28 18:12