深入浅析javascript中的作用域(推荐)


Posted in Javascript onJuly 19, 2016

所谓的作用域,可以简单理解为一个可以读、写的范围(区域),有些js经验的同学可能会说:"js没有块级作用域",js除了全局作用域外,只有函数可以创建作用域。作用域的一个好处就是可以隔离变量。

我们通过一些例子来帮助我们理解js中的作用域。

alert(a);
 var a = 1;

如果对作用域一点不了解的同学可能会说 alert的是1或者报错;但实际上是undefined;

说到这里,我们首先说一下js逐行解析代码之前做的一些准备工作,

js在逐行读代码之前,会做一些“预解析”工作,会先提前找到一些”小东西”,当然”js解析器“不会随便找一些数据的,它会根据var,function,参数来找。

”js解析器“它比较”懒“,在正式运行代码之前都会给var声明的变量赋值为undefined,也就是var a = undefined;会把整个函数看作一个代码块,不去管里边有多少代码。参数等到后边例子中会说。

当所有准备工作都做好后,“JS解析器”就开始逐行执行代码了,现在我们来分析开始的这个例子就很容易明白为什么是undefined了。

再来看下边这个例子

alert(a);
 var a = 1;
 alert(a);
 var a = 2;
 alert(a);

我们来一点点分析这个

首先 ”预解析“: 解析器会找var

读到第二行时 a = undefined;

读到第四行时 依然 a = undefined;

正式逐行执行代码:

第一行 alert:undefined 

第二行 a = 1;

第三行 alert:1;

第五行 alert:2

接着看下边这个例子

alert(a); 
 var a = 1;
 alert(a); 
 function a (){ alert(2); }
 alert(a); 
 var a = 3; 
 alert(a); 
 function a (){ alert(4); }
 alert(a);

我们依然来一点点分析这个

首先 ”预解析“: 解析器会找var function;

读到第二行时 a = undefined;

读到第四行时 a = function a (){ alert(2);} //所有的函数,在正式运行代码之前,都是整个函数块;变量遇到重名的,只留一个变量,如果变量和函数重名,就只留下函数。

读到第六行时,a = function a (){ alert(2);}

读到第八行时,a = function a (){ alert(4);}

正式逐行执行代码:

第一行 alert: function a (){ alert(4);} 

第二行 a = 1; //表达式可以修改预解析的值!

第三行 alert:1;

第四行 函数没有调用,略过;

第五行 alert:1;

第六行 a = 3;

第七行 alert:3

第八行 函数没有调用,略过;

第九行 alert:3

如图所示:

深入浅析javascript中的作用域(推荐)

继续看例子:

var a = 1;
function fn1(){
 alert(a); //undefined   
 var a = 2;
}
fn1();
alert(a); //1

首先 ”预解析“: 解析器会找var function

读到第一行时 a = undefined;

读到第二行时 fn1 = function fn1 (){alert(2);var a = 2;}

正式逐行执行代码: 第一行 a = 1;

第六行 函数调用,进入函数作用域 在函数作用域内依旧是先预解析,再逐行执行

函数内预解析:a = undefined;

执行:alert:undefined;

a = 2; //此时的a仅为函数作用域中的a,不会影响全局中的a

函数执行完毕,回到全局作用域;

第七行 alert:1;

继续:

var a = 1;
function fn1(){
 alert(a); //1  
 a = 2;
}
fn1();
alert(a); //2

这个例子上边那个例子唯一的区别就是函数中的a没有var,只分析其中关键的地方

在函数作用域中 第三行alert(a),由于函数中没有var a,所以"解析器"会到函数的作用域的上一级作用域去寻找a(作用域上下级关系的确定就看函数是在哪个作用域下创建的,在哪个作用域下创建,就是哪个作用域的下级),此时函数的上一级是全局作用域,在全局作用域中,a = 1,所以此时第三行 alert:1,接着第四行,a = 2赋值,依然是函数作用域中没有a, 所以在上一级作用域,也就是全局作用域中找到a,修改全局作用域中的a, 所以会使全局作用域中的a = 2, 因此第七行 alert:2;

这点要理解清楚,注意有无var的区别。

接着来:

var a = 1;
 function fn1(a){
 alert(a); //undefined 
 a = 2;
 }
 fn1();
 alert(a); // 1

这个例子和上一个的区别就是多了个参数,参数的作用相当于局部变量,也就是在函数中预解析会有var a = undefined,所以第三行 alert:undefined,第四行 a = 2 改的是函数作用域中的a,不影响全局中的a,第七行alert:1;

接着:

var a = 1;
function fn1(a){
alert(a); // 1
a = 2;
}
fn1(a);
alert(a); // 1

这个例子又与上一个有些区别,在第六行函数调用时传了个实参进去,第六行函数实参的a是全局变量a = 1的1,函数执行时,第二行 a = 1,所以第三行alert:1,第七行alert:1。

注意这几个例子之间的区别,别混淆了。

再来一个:

var a = 1;
function en(){
var a = 2;
fn();
}
function fn(){
alert(a); //1
}
en();

fn中的a未声明,要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”这个函数的作用域中。

PS:JavaScript中的作用域和上下文概念

javascript中的作用域(scope)和上下文(context)是这门语言的独到之处,这部分归功于他们带来的灵活性。每个函数有不同的变量上下文和作用域。这些概念是javascript中一些强大的设计模式的后盾。然而这也给开发人员带来很大困惑。下面全面揭示了javascript中的上下文和作用域的不同,以及各种设计模式如何使用他们。

上下文 vs 作用域

首先需要澄清的问题是上下文和作用域是不同的概念。多年来我注意到许多开发者经常将这两个术语混淆,错误的将一个描述为另一个。平心而论,这些术语变得非常混乱不堪。

每个函数调用都有与之相关的作用域和上下文。从根本上说,范围是基于函数(function-based)而上下文是基于对象(object-based)。换句话说,作用域是和每次函数调用时变量的访问有关,并且每次调用都是独立的。上下文总是关键字 this 的值,是调用当前可执行代码的对象的引用。

以上所述是小编给大家介绍的javascript中的作用域(推荐),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery异步循环获取功能实现代码
Sep 19 Javascript
javascript中的数字与字符串相加实例分析
Aug 14 Javascript
jquery对单选框,多选框,文本框等常见操作小结
Jan 08 Javascript
关闭时刷新父窗口两种方法
May 07 Javascript
jQuery使用andSelf()来包含之前的选择集
May 19 Javascript
JS实现的页面自定义滚动条效果
Oct 26 Javascript
使用jQuery给input标签设置默认值
Jun 20 Javascript
微信QQ的二维码登录原理js代码解析
Jun 23 Javascript
详解微信小程序入门五: wxml文件引用、模版、生命周期
Jan 20 Javascript
详解动画插件wow.js的使用方法
Sep 13 Javascript
微信小程序 功能函数小结(手机号验证*、密码验证*、获取验证码*)
Dec 08 Javascript
Vue中消息横向滚动时setInterval清不掉的问题及解决方法
Aug 23 Javascript
javascript弹出带文字信息的提示框效果
Jul 19 #Javascript
总结在前端排序中遇到的问题
Jul 19 #Javascript
ECMAScript6快速入手攻略
Jul 18 #Javascript
JavaScript读二进制文件并用ajax传输二进制流的方法
Jul 18 #Javascript
JavaScript暂停和继续定时器的实现方法
Jul 18 #Javascript
jquery+CSS3实现3D拖拽相册效果
Jul 18 #Javascript
完美实现八种js焦点轮播图(下篇)
Apr 20 #Javascript
You might like
linux命令之调试工具strace的深入分析
2013/06/03 PHP
PHP中Fatal error session_start()错误解决步骤
2014/08/05 PHP
php版微信公众平台接口参数调试实现判断用户行为的方法
2016/09/23 PHP
PHP使用PDO访问oracle数据库的步骤详解
2017/09/29 PHP
Apache站点配置SSL强制跳转443
2021/03/09 Servers
javascript 兼容FF的onmouseenter和onmouseleave的代码
2008/07/19 Javascript
制作高质量的JQuery Plugin 插件的方法
2010/04/20 Javascript
js不能跳转到上一页面的问题解决方法
2013/03/01 Javascript
javascript制作幻灯片(360度全景图片)
2015/07/28 Javascript
AngularJS使用ngMessages进行表单验证
2015/12/27 Javascript
Bootstrap开关(switch)控件学习笔记分享
2016/05/30 Javascript
微信小程序 教程之事件
2016/10/18 Javascript
JS瀑布流实现方法实例分析
2016/12/19 Javascript
微信小程序 利用css实现遮罩效果实例详解
2017/01/21 Javascript
MUI 上拉刷新/下拉加载功能实例代码
2017/04/13 Javascript
Vue如何从1.0迁移到2.0
2017/10/19 Javascript
Vue 组件注册实例详解
2019/02/23 Javascript
layui点击左侧导航栏,实现不刷新整个页面,只刷新局部的方法
2019/09/25 Javascript
Python实现的数据结构与算法之基本搜索详解
2015/04/22 Python
Python实现二叉树结构与进行二叉树遍历的方法详解
2016/05/24 Python
对Python中的@classmethod用法详解
2018/04/21 Python
Scrapy-Redis结合POST请求获取数据的方法示例
2019/05/07 Python
如何基于python生成list的所有的子集
2019/11/11 Python
Python3加密解密库Crypto的RSA加解密和签名/验签实现方法实例
2020/02/11 Python
Python2与Python3关于字符串编码处理的差别总结
2020/09/07 Python
OpenCV灰度化之后图片为绿色的解决
2020/12/01 Python
Marriott中国:万豪国际酒店查询预订
2016/09/02 全球购物
美国购买肉、鸭、家禽、鹅肝和熟食网站:D’Artagnan
2018/11/13 全球购物
毕业生的自我评价
2013/12/30 职场文书
餐馆开业致辞
2015/08/01 职场文书
2016年教师节感言
2015/12/09 职场文书
护士自荐信范文(2016推荐篇)
2016/01/28 职场文书
redis 限制内存使用大小的实现
2021/05/08 Redis
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
2022/04/11 Vue.js
Golang实现可重入锁的示例代码
2022/05/25 Golang
Mysql中的触发器定义及语法介绍
2022/06/25 MySQL