深入知晓JavaScript的作用域问题

JavaScript会沿着作用链向上寻找自己的定义
服务器君一共花费了219.048 ms进行了5次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

每个写过程序的人都不会对作用域这个概念陌生,那在这篇文章中就来谈下Javascript的作用域。

在Javascript,全局环境本身就一个对象。在浏览器宿主中这个对象是window,而当Javascript用于其它非浏览器的宿主,如嵌入式的环境中,可能会是其它的对象。

在这里也纠正一个观念,有很多人都认为Javascript只在浏览器中使用,其实Javascript也能在很多非Web情况下使用,据介绍Javascript在一些基于嵌入式的应用领域表现得也很出色,当然这些我也只是听过传说而已。

言归正传,当我们写下:var i=1时,其实就是声明了一个window作用域的一个变量。

而当我们写下i=1时,是声明了一个window的属性。

看这样一段代码:

<script type="text/javascript">
	var a = "hello";
	b = "world";
	Test();
	
	function Test() 
	{
		alert(a + " " + b);
		var a = "welcome";
			b = "china";
		alert(a + " " + b);
	}
	alert(a + " " + b);
</script>  

这段代码分别输出的结果是:undefined world,welcome china, hello china.

我们来分别解释:

在上文中,我们说过,在Javascript预编译时,会把所有var变量创建,默认值为undefined,我们在这里可以举一个例子:

我们可以写这样一段代码:

<script type="text/javascript">
	alert(a);
	alert(b);
	var a = "111";
        b = "111";
</script>  

当我们执行运行这段脚本时,可以发现,首先弹出undefined,然后回提示脚本错误,提示b不存在。由此就可以表明,a在预编译的过程中就已经被创建并且初始化为undefined,而b却只能在实际运行时按顺序去解释。其实在预编译后的Javascript代码可以近乎理解如下:

<script type="text/javascript">
	var a = undefined;
	alert(a);
	alert(b);
	a = "111";
	b = "111";
</script>  

接下来我们可以谈一下函数的作用域问题,每当代码运行进入一个函数时,Javascript引擎就会自动创建一个新的作用域,然后把这个新作用域作为当前作用域的子作用域,然后把当前的代码作用域切换到这个新作用域。当代码退出函数时,这个作用域销毁,把代码作用域交还给他的父作用域。

好,准备工作差不多了,接下来我们就来解释第一个问题:问什么会输出undefined world。

首先代码进行在预编译,当进入 Test方法时,开启一个新作用域,然后把全局作用域作为他的父作用域。然后对Test内的方法进行预编译,和上面的代码一样,Test方法被预编译后方法体大致如下:

function Test() {
    var a = undefined;
    alert(a + " " + b);
    var a = "welcome";
    b = "china";
    alert(a + " " + b);
}  

当然,在当前作用域下无法找到b,于是他就会到他的父作用域下,也就是全局作用域找到了b=“world”。于是也就产生了这样的结果。

第二次弹出welcome china,没什么好说的。

第三次,弹出hello china。我们可以这样理解,var a 只是 方法Test的一个局部变量,而b由于事先未声明,因此他会去父作用域中去找到对应的定义。

好,接下来,我们再看一下这个方法的若干个变体。

<script type="text/javascript">
	var a = "hello";
        b = "world";
	Test();
	
	function Test() 
	{
		alert(a + " " + b);
		a = "welcome";
		b = "china";
		alert(a + " " + b);
	}
	alert(a + " " + b);
</script>  

首先,我们将方法体内的var a改成a,我们先不看答案,直接来分析,首先,在预编译阶段,方法体内几乎没有任何改变,因此此时a和b一样,都要去他们的父作用域中去寻找,因此第一次出的结果应该是hello world,第二次没什么说的:welcome china,第三次由于a和b在本作用域内都没有事先定义,因此都是再改变父作用域内的值,因此应该输出welcome china.

我们继续:

<script type="text/javascript">
	var a = "hello";
        b = "world";
	Test();
	
	function Test() 
	{
		alert(a + " " + b);
		var a = "welcome";
		var b = "china";
		alert(a + " " + b);
	}
	
	alert(a + " " + b);
</script>  

和上面的分析一样,应该输出undefined undefined,welcome china,hello world.

<script type="text/javascript">
	a = "hello";
	b = "world";
	Test();
	
	function Test() 
	{
		alert(a + " " + b);
		var a = "welcome";
		b = "china";
		alert(a + " " + b);
	}
	
	alert(a + " " + b);
</script>  

应该是undefined china,welcome china,hello china.

经试验,都没问题。

因此我们可以得出,每个变量在找不到自己的定义时,都会沿着作用链向上寻找,这样就很可能会出现未预知的错误,给排错添加了很多困难。更麻烦的是,还可能会对父作用域上的变量值进行修改,因此我们在声明变量时应该尽量加上var,尽管Javascript并不强迫我们这样做。

本文地址:http://www.nowamagic.net/librarys/veda/detail/1230,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1230

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《大话数据结构》 程杰 (作者)

《大话数据结构》主要内容包含:数据结构介绍、算法推导大O阶的方法;顺序结构与链式结构差异、栈与队列的应用;串的朴素模式匹配、KMP模式匹配算法;二叉树前中后序遍历、赫夫曼树及应用;图的深度、广度遍历;最小生成树两种算法、最短路径两种算法;拓扑排序与关键路径算法;折半查找、插值查找、斐波那契查找等静态查找;稠密索引、分块索引、倒排索引等索引技术;二叉排序树、平衡二叉树等动态查找;B树、B+树技术,散列表技术;冒泡、选择、插入等简单排序;希尔、堆、归并、快速等改进排序。

更多计算机宝库...