文档章节

javascript的作用域链

贰拾壹
 贰拾壹
发布于 2015/02/12 09:39
字数 1333
阅读 111
收藏 6

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

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

开始。

在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__去找也就是全局作用域了,如果还是找不到,没有办法了,直接出错了。是不是很原型链有的一拼。

哈哈,结束。

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

© 著作权归作者所有

贰拾壹
粉丝 9
博文 5
码字总数 2910
作品 1
长春
程序员
私信 提问
JavaScript的变量作用域

在学习JavaScript的变量作用域之前,我们应当明确几点: JavaScript的变量作用域是基于其特有的作用域链的。 JavaScript没有块级作用域。 函数中声明的变量在整个函数中都有定义。 1、JavaS...

biGpython
2011/08/13
0
0
《前端面试手记》之JavaScript基础知识梳理(下)

👇 内容速览 👇 实现ES5继承的4种方法 原型和原型链 作用域和作用域链 Event Loop 执行上下文 闭包的理解和分析 🔍查看全部教程 / 阅读原文🔍 ES5继承 题目:ES5中常用继承方法。 方...

godbmw
04/03
0
0
图解Javascript上下文与作用域

本文尝试阐述Javascript中的上下文与作用域背后的机制,主要涉及到执行上下文(execution context)、作用域链(scope chain)、闭包(closure)、等概念。 >> 原文 << Execution context 执...

rainyear
2015/07/06
0
7
《高性能javascript》 笔记

第一部分:关于script 当把js脚本通过script标签放在head中的时候,早期浏览器在遇到script的时候会阻止浏览器加载和渲染html。知道javascript脚本被下载并执行完,且这些javascript是依次下载和...

modernizr
2014/04/03
467
1
好程序员Web前端培训入门之JS基础知识梳理汇总

好程序员Web前端入门之JS基础知识梳理汇总,Web前端工程师是当前各大企业都比较稀缺的人才,薪资待遇和就业前景都很不错。不论是专业还是非专业,有基础亦或是无基础,都想通过学习Web前端实...

好程序员IT
03/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot+jpa 错误信息org.springframework.beans.factory.BeanCreationException

报错信息 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/a......

冥焱
19分钟前
1
0
威胁快报|新兴挖矿团伙借助shodan作恶,非web应用安全再鸣警钟

近日,阿里云安全发现了一个使用未授权访问漏洞部署恶意Docker镜像进行挖矿的僵尸网络团伙。我们给这一团伙取名为Xulu,因为该团伙使用这个字符串作为挖矿时的用户名。 Xulu并不是第一个攻击...

迷你芊宝宝
26分钟前
1
0
十大经典排序算法动画与解析

排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序。 内部排序是数据记录在内存中进行排序。 而外部排序是因排序的数据很大,一次不能容纳全部的排序记...

夜黑人模糊灬
29分钟前
4
0
7. java枚举

1. 枚举是什么 有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便 2. 为什么不用静态常量来替代枚举类呢? 3. 常用方式 3.1 方式1 枚举类: package cn.ali.tencent...

20190513
30分钟前
1
0
elasticsearch – 弹性搜索:“Term”,“Match Phrase”和“Query String”之间的差异

术语查询匹配单个术语,因为它是:不分析值。 所以,它不必根据你索引的情况而降低。 如果您在索引时间提供Bennett并且未分析该值,则以下查询将不返回任何内容: { "query": { "te...

xiaomin0322
36分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部