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 相关文章推荐
JavaScript实现点击按钮后变灰避免多次重复提交
Jul 15 Javascript
JS+CSS实现精美的二级导航效果代码
Sep 17 Javascript
jQuery仅用3行代码实现的显示与隐藏功能完整实例
Oct 08 Javascript
JavaScript编写简单的计算器
Nov 25 Javascript
微信小程序 chooseImage选择图片或者拍照
Apr 07 Javascript
js表单序列化判断空值的实例
Sep 22 Javascript
JavaScript类数组对象转换为数组对象的方法实例分析
Jul 24 Javascript
js实现网页同时进行多个倒计时功能
Feb 25 Javascript
vue基础之事件v-onclick="函数"用法示例
Mar 11 Javascript
使用JS判断页面是首次被加载还是刷新
May 26 Javascript
微信小程序 简易计算器实现代码实例
Sep 02 Javascript
vue用elementui写form表单时,在label里添加空格操作
Aug 13 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
PHP安装问题
2006/10/09 PHP
PHP中GET变量的使用
2006/10/09 PHP
php max_execution_time执行时间问题
2011/07/17 PHP
PHP使用正则表达式清除超链接文本
2013/11/12 PHP
php创建和删除目录函数介绍和递归删除目录函数分享
2014/11/18 PHP
PHP中类的自动加载的方法
2017/03/17 PHP
JS延迟加载(setTimeout) JS最后加载
2010/07/15 Javascript
网页中CDATA标记的说明
2010/09/12 Javascript
jQuery中json对象的复制方式介绍(数组及对象)
2013/06/08 Javascript
js实现二代身份证号码验证详解
2014/11/20 Javascript
jQuery实现左右切换焦点图
2015/04/03 Javascript
js实现纯前端的图片预览
2016/04/27 Javascript
全国省市二级联动下拉菜单 js版
2016/05/10 Javascript
利用angular.copy取消变量的双向绑定与解析
2016/11/25 Javascript
JS中解决谷歌浏览器记住密码输入框颜色改变功能
2017/02/13 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
Ionic + Angular.js实现图片轮播的方法示例
2017/05/21 Javascript
React进阶学习之组件的解耦之道
2017/08/07 Javascript
Vue2几种常见开局方式详解
2017/09/09 Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
2020/05/06 Javascript
MySQLdb ImportError: libmysqlclient.so.18解决方法
2014/08/21 Python
Python写的英文字符大小写转换代码示例
2015/03/06 Python
Python 找到列表中满足某些条件的元素方法
2018/06/26 Python
Python实现的爬取百度贴吧图片功能完整示例
2019/05/10 Python
python-tornado的接口用swagger进行包装的实例
2019/08/29 Python
python中如何进行连乘计算
2020/05/28 Python
python跨文件使用全局变量的实现
2020/11/17 Python
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
印度尼西亚电子产品购物网站:Kliknklik
2018/06/05 全球购物
法国购买隐形眼镜和眼镜网站:Optical Center
2019/10/08 全球购物
怀旧香味蜡烛:Homesick
2019/11/02 全球购物
亚马逊新加坡官方网站:Amazon.sg
2020/03/25 全球购物
工厂总经理岗位职责
2014/02/07 职场文书
公司采购主管岗位职责
2014/06/17 职场文书
小学生国庆演讲稿
2014/09/05 职场文书
安全员岗位职责范本
2015/04/11 职场文书