Javascript中的作用域和上下文深入理解


Posted in Javascript onJuly 03, 2015

概述

Javascript中的作用域和上下文的实现是Javascript语言独有的特性,从某种程度上来说,Javascript语言是十分灵活的。Javascript中的函数可以采用各种各样的上下文,作用域也可以被封装和保存。正是由于这些特性,Javascript中也提供了很多很有用的设计模式。然而,作用域和上下文也是Javascript程序员在开发中经常迷惑的地方。
下面会向大家介绍Javascript中作用域和上下文的概念,以及它们的不同。

作用域 VS 上下文

首先要说明的很重要的一点是作用域和上下文并不是同一个概念,它们指代的并不是同一个东西。作为一个前端的菜逼,经常会看到一些文章把这两个概念弄混,结果有些东西越看越不明白。这两个概念貌似被混淆了很长一段时间了。因此,查了很多资料,简单说明下这两个概念。:stuck_out_tongue_closed_eyes:
在Javascript中,当一个函数被调用时都会有一个作用域和上下文和这个函数绑定在一起。从根本上来说,作用域是基于函数的而上下文是基于对象的。换句话说,作用域适用于函数被调用时函数中变量的访问权限。上下文通常是指“this”关键字的值,“this”是拥有当前执行代码的对象的引用。

变量作用域

变量可以被定义在局域或全局作用域中,分别称为局部变量和全局变量。全局变量是指在函数体外声明的变量,在程序的任何地方都可以访问全局变量。局部变量是指在函数体内定义的变量,它仅可以在函数体内或者嵌套的函数内被访问,并且不能在函数外部被访问。
Javascript目前并不支持块级作用域(在if、switch、for等语句中定义的变量)。这意味着在块内定义的变量,在块外也可以访问。但是,在ES6中,我们可以使用“let”关键字定义块级作用域。
关于作用域的内容,大家可以查下别的资料,这部分内容相对简单些。

“this”上下文

上下文(context)通常取决于函数被调用的方式。当函数作为对象的方法被调用时,“this”指代的是调用该函数的对象。

var obj={

    foo:function (){

        console.log(this === obj);

    }

};

obj.foo();   //输出true

同样,当我们使用“new”关键字创建新对象时,this引用的是新创建的对象。
function foo(){

    console.log(this);

}

foo();         //输出window

var obj=new foo();     //输出 foo {}

有一点需要注意的是,当全局作用域中的函数被被调用时,this引用的是全局对象,在浏览器环境中指的就是window。但是,如果在严格模式下运行代码时,“this”被设置为“undefined”
执行上下文(Execution Context)

Javascript是单线程的语言,这也就是说Javascript在浏览器中运行时,一次只能做一件事情,其他的事情将被方法队列中,等待被处理。

1.当Javascript代码文件被浏览器载入后,默认最新进入的是一个全局的执行上下文。当在全局上下文中调用一个函数时,程序留就进入该被调用函数内,此时Javascript引擎就会为该函数创建一个新的执行上下文,并且将其压入到执行上下文堆栈的顶部。浏览器总是执行当前在堆栈顶部的上下文,一旦执行完毕,该上下文就会从堆栈顶部被弹出,然后,进入其下的上下文执行代码。这样,堆栈中的上下文就会被依次执行并且弹出堆栈,直到回到全局的上下文。

2.一个执行上下文可以被分为两个阶段:创建阶段和执行阶段。在创建阶段,javascript解释器首先会创建一个变量对象(也成为“活动对象”,activation object)。活动对象由变量,函数声明和参数组成。在这个阶段,函数的作用域链被初始化,this引用的对象也被确定。接下来就是执行阶段,在这个阶段,代码被解释并执行。
在Javascript代码中,可以有任意多个函数上下文,我们已经知道,当函数被调用时,Javascript解释器就会创建一个新的上下文,同时会创建一个私有的作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问。

3.通过上面的解释,我们对函数的“执行上下文”有了一个基本的概念,但是这里也是大家最容易迷惑的一个地方。Javascript中的“执行上下文”主要是指作用域,而不是上面第四小节中指的“this上下文”。类似的容易混淆的概念在Javascript中还有很多,但是我们只要弄清楚了每个概念所指代的具体对象,就不会再迷惑,因此,这里也希望大家能够真正的区分开“执行上下文”和“this上下文”。

简单的一句话概括来说,执行上下文是与作用域相关的概念,虽然这样说可能不太严谨。

作用域链

对每一个执行上下文来说,都有一个作用域连跟它绑定在一起。作用域链包含了执行上下文堆栈中的执行上下文活动对象(activation object,听起来有点绕口)。作用域链决定了变量的访问和标识符的解析。

代码示例:

function first(){

    second();

    function second(){

        third();

        function third(){

            fourth();

            function fourth(){

                //代码

            }

        }

    }

}

first();

执行上面的代码,嵌套的函数都会被执行。就上面的代码来说,也会形成一个作用域链,作用域链从顶部到底部的顺序为:fourth, third, second, first, global。函数fourth可以访问全局作用域中的变量,并且可以访问函数third, second, first中定义的任何变量。
有一点需要注意的是,在函数体内,局部变量的优先级高于同名的全局变量。如果在函数内声明的局部变量或函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所覆盖。
简单来说,每次我们尝试访问一个变量时,程序都会在当前函数作用域内查找变量,如果找不到就沿着作用域链到该函数的上层去查找,直到找到该变量为止,如果找不到则返回undefined。

总结

这篇文章介绍了javascript中上下文和作用域的相关概念,javascript中还有几个比较重要的概念,如闭包等,这些在以后自己弄明白了会写成文章~~

Javascript 相关文章推荐
jQuery 获取URL的GET参数值的小例子
Apr 18 Javascript
Js实现网页键盘控制翻页的方法
Oct 30 Javascript
Javascript前端UI框架Kit使用指南之kitjs事件管理
Nov 28 Javascript
Bootstrap每天必学之缩略图与警示窗
Nov 29 Javascript
JavaScript高级程序设计(第三版)学习笔记1~5章
Mar 11 Javascript
手机端实现Bootstrap简单图片轮播效果
Oct 13 Javascript
Vuex2.0+Vue2.0构建备忘录应用实践
Nov 30 Javascript
详解基于mpvue的小程序markdown适配解决方案
May 08 Javascript
vue.js添加一些触摸事件以及安装fastclick的实例
Aug 28 Javascript
vue实现pdf导出解决生成canvas模糊等问题(推荐)
Oct 18 Javascript
使用webpack编译es6代码的方法步骤
Apr 28 Javascript
js实现磁性吸附的示例
Oct 26 Javascript
JavaScript访问字符串中单个字符的两种方法
Jul 03 #Javascript
JavaScript中解析JSON数据的三种方法
Jul 03 #Javascript
一张Web前端的思维导图分享
Jul 03 #Javascript
JavaScript中的对象与JSON
Jul 03 #Javascript
javascript生成大小写字母
Jul 03 #Javascript
jQuery切换所有复选框选中状态的方法
Jul 02 #Javascript
javascript带回调函数的异步脚本载入方法实例分析
Jul 02 #Javascript
You might like
ZF框架实现发送邮件的方法
2015/12/03 PHP
js 获取坐标 通过JS得到当前焦点(鼠标)的坐标属性
2013/01/04 Javascript
jquery.cookie() 方法的使用(读取、写入、删除)
2013/12/05 Javascript
jQuery学习笔记之 Ajax操作篇(三) - 过程处理
2014/06/23 Javascript
jQuery内容过滤选择器用法分析
2015/02/10 Javascript
Bootstrap Table的使用总结
2016/10/08 Javascript
Angular指令之restict匹配模式的详解
2017/07/27 Javascript
vue v-model实现自定义样式多选与单选功能
2018/07/05 Javascript
VUE-Table上绑定Input通过render实现双向绑定数据的示例
2018/08/27 Javascript
highCharts提示框中显示当前时间的方法
2019/01/18 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
vue eslint简要配置教程详解
2019/07/26 Javascript
es6中使用map简化复杂条件判断操作实例详解
2020/02/19 Javascript
vue.js 解决v-model让select默认选中不生效的问题
2020/07/28 Javascript
详解为什么Vue中的v-if和v-for不建议一起用
2021/01/13 Vue.js
[01:02:54]完美世界DOTA2联赛PWL S2 FTD vs GXR 第一场 11.22
2020/11/26 DOTA
[49:15]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第二场 1月19日
2021/03/11 DOTA
详细解析Python当中的数据类型和变量
2015/04/25 Python
详解Python爬虫的基本写法
2016/01/08 Python
十行代码使用Python写一个USB病毒
2019/06/21 Python
基于python3监控服务器状态进行邮件报警
2019/10/19 Python
Python将列表中的元素转化为数字并排序的示例
2019/12/25 Python
浅谈sklearn中predict与predict_proba区别
2020/06/28 Python
Django如何实现密码错误报错提醒
2020/09/04 Python
html5 web本地存储将取代我们的cookie
2012/12/26 HTML / CSS
浅谈关于html5中图片抛物线运动的一些心得
2018/01/09 HTML / CSS
化石印度尼西亚在线商店:Fossil Indonesia
2019/03/11 全球购物
周仰杰(JIMMY CHOO)法国官方网站:闻名世界的鞋子品牌
2019/09/27 全球购物
澳大利亚顶级美发和美容贸易超市:glamaCo
2020/01/19 全球购物
易程科技软件测试笔试
2013/03/24 面试题
三八节标语
2014/06/27 职场文书
土建专业毕业生自荐书
2014/07/04 职场文书
员工三分钟演讲稿
2014/08/19 职场文书
安徽导游词
2015/02/12 职场文书
MySQL 开窗函数
2022/02/15 MySQL
前端JS获取URL参数的4种方法总结
2022/04/05 Javascript