js 作用域是前端开发必掌握的基础知识。这篇文章主要介绍了 javascript 中的作用域的相关资料, 需要的朋友可以参考下
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
所谓的作用域,可以简单理解为一个可以读、写的范围 (区域), 有些 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
如图所示:
继续看例子:
- 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 中的作用域 (推荐),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 phperz 网站的支持!
来源: http://www.phperz.com/article/17/0331/264218.html