热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javascript的作用域链

最近一直想整理几篇好的文章分享给大家,无奈文笔太俗,也是一直懒惰。直到今天才稍微有个样子写出来,因为明天就不上班了。本文都是自己平时经验积累,难免错误,欢迎指正,请勿拍砖。开始。在

最近一直想整理几篇好的文章分享给大家,无奈文笔太俗,也是一直懒惰。直到今天才稍微有个样子写出来,因为明天就不上班了。

本文都是自己平时经验积累,难免错误,欢迎指正,请勿拍砖。

开始。

在Javascript中,如果说原型链是对象寻找属性的过程,那么作用域链就是在作用域内寻找变量的过程,那么属性和变量又有什么不同吗?

下面举个例子:

function test(){
    var a=1;
}
var obj={b:2}

上面函数test中的a就是变量,使用var 关键字定义,上面的obj对象中的b就是属性,可以知道属性b属于obj这个对象,那么变量a属于哪个对象吗?答案是肯定的,变量a 也是属于某个对象的,接下来我们会介绍这个对象。

介绍这个对象之前,我们必须要了解一下函数的的执行过程,每个函数对应着一个执行上下文,函数执行的过程有两个阶段,一是进入执行上下文,二是执行代码。

进入执行上下文,每个函数都会对应着一个上下文对象(我们姑且这么叫),这个对象有个VO 属性(我们也姑且这么叫),在本函数内定义的变量都是这个VO对象的属性,当然上下文对象和VO对象还有其他的属性内容。

下面通过实例了解一下上下文对象以及VO对象。

function test(i){
    alert(x); // function
    var x = 10;
    alert(x); // 10
    function x() {};
    alert(x); // 10
}
test(10);

很多同学对上面的代码运行结果可能有些疑惑,我们来分析一下上面代码中test函数对应的上下文对象以及VO对象。

第一阶段,进入执行上下文

testExecutiOnContext= {
            VO: {
                arguments: {
                      0:10
                      length: 1
                },
                x: pointer to function x(),
            },
            scopeChain: { ... },
            this: { ... }
} 

第二阶段,执行代码


testExecutiOnContext= {
            VO: {
                arguments: {
                      0:10
                      length: 1
                },
                x: 10,
            },
            scopeChain: { ... },
            this: { ... }
}

依据这个分析,我们不难得出上面的函数运行结果了。

下面说点题外话

var a=10;
b=12;
上面这个代码有何不同呢?有人可能会说,这是定义了两个全局的变量,其实不然,前者是一个全局变量,后者只是为window对象定义了一个属性。但它们到底何不同呢?这里通过执行上下文就能清晰分析出它们的不同之处
alert(a);//undefined
var a=10;
alert(b);//脚本错误
b=10;
看见了吧,这就是区别,用上下文的方式分析一下。

进入执行上下文,b根本就不在VO对象当中。

VO = {
  a: undefined
};
执行代码阶段,才有这个两个值。
VO = {
  a: 10
  b:10
};

下面回到正题,说作用域链,既然是链,那就不能是一个东西,必须是一串东西。

上例子:

function a(){
	var aa="aa";
	function b(){
		var bb="bb";
		function c(){
			var cc="cc";
			alert(aa);
			alert(bb);
			alert(cc);
		}
		c()
	}	
	b();
}
a();
我们上面的代码,我们在函数c 里面可以使用函数b,函数a里面的变量 bb和aa。其实这就一个链,一层一层的链状结构,内部函数可以使用外部函数的变量。这很简单,下面稍微深入讨论一下原理。


每个函数都有个内部的属性__parent__,这个属性是我们用浏览器访问不到的,如果要访问可以使用Rhino解释器来执行下面的代码。关于这个东西,网上自行搜索吧。

__parent__属性可以获取“上级函数”的VO对象,有些拗口,用上面的例子说吧,函数c,c.__parent__ 就是函数b对应的上下文的VO对象


function a(){
	var aa="aa";
	function b(){
		var bb="bb";
		function c(){
			var cc="cc";
			for(var i in c.__parent__){//这里是函数b的VO对象
				println(i);	//分别是arguments,bb,c
			}
		}
		c()
	}	
	b();
}
a();

上面println(Rhino没有alert)的结果就是函数b对应的VO对象,里面包含参数对象,bb变量,和函数c。


同理,c.__parent__.__parent__ 对应的就是函数a的VO对象
改写上面的代码:
for(var i in c.__parent__.__parent__){//这里就是函数a的VO对象
	println(i);	//分别是arguments,aa,b
}

到这里我们就得出原理,也对作用域链以及作用域寻找变量的过程应该比较清晰了。

下面对上面的a,b,c函数的作用域画个图简单了解一下。

技术分享

通过上面的图解,我们就可以清晰的发现这确实是一个链,例如:c函数寻找一个变量,会现在c函数的VO对象里面寻找,找不到的话,去c.__parent__也就是b函数的VO对象上寻找,再找不到的话会去c.__parent__.__parent__上也就是a函数的VO对象去找,再找不到的话就回去c.__parent__.parent__.parent__去找也就是全局作用域了,如果还是找不到,没有办法了,直接出错了。是不是很原型链有的一拼。

哈哈,结束。

时间匆匆,难免错误,编辑器也永不好,还望见谅,祝大家新年快乐。

Javascript的作用域链


推荐阅读
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
author-avatar
mobiledu2502855037
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有