深入浅析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 相关文章推荐
解决AJAX中跨域访问出现'没有权限'的错误
Aug 20 Javascript
jQuery切换网页皮肤并保存到Cookie示例代码
Jun 16 Javascript
原生JS封装ajax 传json,str,excel文件上传提交表单(推荐)
Jun 21 Javascript
AngularJS ng-change 指令的详解及简单实例
Jul 30 Javascript
通过sails和阿里大于实现短信验证
Jan 04 Javascript
详解angular笔记路由之angular-router
Sep 12 Javascript
详解vue axios中文文档
Sep 12 Javascript
JS路由跳转的简单实现代码
Sep 21 Javascript
AngularJS $http post 传递参数数据的方法
Oct 09 Javascript
详解django模板与vue.js冲突问题
Jul 07 Javascript
vue实现拖拽的简单案例 不超出可视区域
Jul 25 Javascript
Vue中Object.assign清空数据报错的解决方案
Mar 03 Vue.js
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
一个简单的PHP投票程序源码
2007/03/11 PHP
PHP面向对象的进阶学习(抽像类、接口、final、类常量)
2012/05/07 PHP
浅析PHP原理之变量(Variables inside PHP)
2013/08/09 PHP
PHP join()函数用法与实例讲解
2019/03/11 PHP
Laravel5.1 框架路由基础详解
2020/01/04 PHP
Thinkphp 框架扩展之应用模式实现方法分析
2020/04/27 PHP
浅谈PHP之ThinkPHP框架使用详解
2020/07/21 PHP
理解Javascript_01_理解内存分配原理分析
2010/10/11 Javascript
JavaScript类型转换方法及需要注意的问题小结(挺全面)
2010/11/11 Javascript
有关JavaScript的10个怪癖和秘密分享
2011/08/28 Javascript
web基于浏览器的本地存储方法应用
2012/11/27 Javascript
JS实现简易图片轮播效果的方法
2015/03/25 Javascript
怎么通过onclick事件获取js函数返回值(代码少)
2015/07/28 Javascript
原生javascript+css3编写的3D魔方动画旋扭特效
2016/03/14 Javascript
jQuery 监控键盘一段时间没输入
2016/04/22 Javascript
Bootstrap实现带动画过渡的弹出框
2016/08/09 Javascript
js手机号批量滚动抽奖实现代码
2020/04/17 Javascript
jQuery插件FusionCharts绘制的2D条状图效果【附demo源码】
2017/05/13 jQuery
Angularjs在360兼容模式下取数据缓存问题的解决办法
2017/06/22 Javascript
详解Angular4 路由设置相关
2017/08/26 Javascript
浅谈VUE单页应用首屏加载速度优化方案
2018/08/28 Javascript
vue将data恢复到初始状态 && 重新渲染组件实例
2020/09/04 Javascript
Vue 3.0中jsx语法的使用
2020/11/13 Javascript
Python中操作mysql的pymysql模块详解
2016/09/13 Python
Python如何读取MySQL数据库表数据
2017/03/11 Python
Python简单操作sqlite3的方法示例
2017/03/22 Python
python OpenCV学习笔记之绘制直方图的方法
2018/02/08 Python
对Python 除法负数取商的取整方式详解
2018/12/12 Python
python开发准备工作之配置虚拟环境(非常重要)
2019/02/11 Python
python matplotlib如何给图中的点加标签
2019/11/14 Python
Python新手学习装饰器
2020/06/04 Python
html5 postMessage前端跨域并前端监听的方法示例
2018/11/01 HTML / CSS
2014年学雷锋活动总结
2014/06/26 职场文书
家具商场的活动方案
2014/08/16 职场文书
2015年世界无烟日活动总结
2015/02/10 职场文书
2015年评职称个人工作总结
2015/10/15 职场文书