您的位置:首页 > Web前端 > JavaScript

理解 javascript 作用域

2013-10-11 17:28 204 查看
对于作用域的话,我觉得就是一些变量能够被访问或者操作的一个区域。如果超过这个区域的话,它似乎就没有了利用价值了。

作用域前的准备
在了解作用域前,我们来说一下题外话。
1.可执行代码:有三种:(1)全局代码  (2)函数代码  (3)eval函数

2.执行环境:每当javascript解析器进入可执行代码的时候,它就会为它创建一个执行环境,也称执行上下文

3.变量对象:执行环境中的变量和函数都是保存到整个对象中的,还有一点就是我们不能用javascript代码去访问整个对象,但是解析器在访问的时候会在后台使用它。

4.活动对象:当执行环境是函数的时候,那么函数被调用的时候,该活动对象也就是被创建,并且把它作为变量对象。

进入这篇文章的作用域
上面为了作用域这个概念铺垫了很久了。那好,我们来讲下作用域这个似乎很抽象的概念。每当javascript解析器进入到一个执行环境的时候,就会为变量对象创建一个作用域链。作用域链的前端总是该执行环境所对应的变量对象,然后作用域链下一个变量对象来着外部的环境,而下一个变量对象就来着下一个外部的环境,一直到全局执行环境就停止。(摘自《javascript高级程序设计》)其实也就是外部的执行环境就是它所包含的执行环境的父环境。然后在寻找变量的时候会沿着作用域一级一级去寻找,从作用域链的前端到全局执行环境,如果找不到就报错,如果找到就不向下寻找了。

我们先来看看一个例子来了解上面很抽象的解释:

var name = 'monkind';
(function fun(){
alert(name);//monkind
})();

上面弹出来的就是monkind不是undefined,记住这个,下面待会有一个跟它很相似的。用上面的理论我们可以理解:在全局代码中创建一个执行环境和作用域链,然后执行环境相关联的变量对象把name还有fun函数设置为属性并赋值。然后就是自执行函数fun的运行,也创建一个执行环境,它会创建活动对象,再把当前的执行环境放在作用域链的最前端,外面就是全局执行环境。当要访问name这个变量的时候,javascript解析器会沿着作用域访问下去,在fun函数中找不到,就只能到全局执行环境也就是window找了。
javascript没有块级作用域
什么是块级作用域,就是用花括号封闭的代码有自己的执行环境和作用域,一旦离开花括号的话就会自动销毁里面的变量等,但是不要跟函数作用域混淆,块级作用域不包含函数的,只有if和for语句。但是偏偏javascript就要搞特殊。来,我们来看下面的代码:

if (true) {
var j = '19';
for (var k = 0; k < 10; k++) {
}
}
console.log(k + '...last');
console.log(j + '....j');


如果它没有块级作用域的话,那么他的k和j的值是什么?



其实上面的代码相当于这样子写的:

var j = '19', k = 0;
if (true) {
for (; k < 10; k++) {
}
}
console.log(k + '...last');
console.log(j + '....j');


我们再看下下面的代码,它弹出来会是哪个值呢?

if (true) {
var j = '19';
for (var k = 0; k < 10; k++) {
}
}
function fun(){
alert(k);
}
fun();

没错,它还是弹出来10,为什么呢?这个就留给读者慢慢琢磨了,原理都在上面了。

javascript词法作用域
对于一些新的专业名称,我第一反应就是它究竟是什么?不喜欢太专业太权威的解释,用比较淳朴的语言或者举个例子来解释容易让菜鸟懂呀。对于词法作用域就是javascript执行环境的作用域是从定义它的时候就确定下来了,而不是在它运行的时候。作为第一次看见这个解释之后我还是很懵懂呀,不知道你们会不会呀,我觉得应该举一两个例子来解释下。

var name = 'monkind';
function myName() {
alert(name);
}

function callMyName() {
var name = 'zkh';
myName();
}
callMyName();

那么究竟会弹出来那个name呢?是monkind还是zkh呢?事实上弹出的是monkind。那么为什么呢?我们要知道myName这个函数在全局执行环境定义的,所以它的作用域就是全局执行环境的,虽然它执行的是在callMyName函数中,但是记住javascript是词法作用域。那么当然不能访问callMyName函数中的name啦,只能访问全局环境的name也就是monkind。

回应上面的那句"记住这个,下面待会有一个跟它很相似的",我们再来看下一个例子,也是很经典的例子。

var name = 'monkind';
(function fun(){
alert(name);
var name = 'zkh';
alert(name);
})();


第一个弹出的窗口是"undefined",第二个是"zkh";那么为什么第一个alert不去访问全局的name呢?我们首先要去了解一个就是:javascript引擎会先对执行环境中的变量和函数进行定义,如果没有赋值的话就设置为undefined。所以fun函数中的name对该函数是可见的,在词法分析后的构造作用域链中,会把name放在fun函数的执行环境中。所以第一个访问就是还没赋值的undefined,要访问第二个name的时候,name已经赋值给"zkh"了,大家可以用chrome开发者工具的断点去看。



这个是在第一个alert断点的情况。

感谢那些好的文章还有书籍,给我写作的动力。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: