博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript的作用域链
阅读量:6944 次
发布时间:2019-06-27

本文共 2710 字,大约阅读时间需要 9 分钟。

  hot3.png

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

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

开始。

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

哈哈,结束。

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

转载于:https://my.oschina.net/mam/blog/377889

你可能感兴趣的文章
Postfix系列一:基本配置和别名配置(编译安装)
查看>>
web服务器之压力测试工具
查看>>
Windows8 开发者预览版与Windows7完美共存安装指南
查看>>
XSS漏洞到底是什么
查看>>
OCP11g 参考图书 题库及错误答案释疑
查看>>
snort在freebsd上的安装
查看>>
用Access数据库开发《人生少后悔管理系统》
查看>>
iOS Block小结
查看>>
这个王妃不好当
查看>>
Delphi 中的 XMLDocument 类详解(17) - 上一个节点、下一个节点、父节点
查看>>
python: install mysqldb
查看>>
rsync
查看>>
挖掘源代码的价值
查看>>
如何让你的VIM支持中文不乱码
查看>>
jdk源码(二):你知道ConcurrentHashMap的具体实现细节吗?
查看>>
Linux下查看占用CPU最高的进程和占用内存最高的进程
查看>>
我的友情链接
查看>>
在线编辑器 上传控件
查看>>
系统返回按钮事件拦截
查看>>
1.Cisco ACS5.2安装
查看>>