26857303的专栏

其实呢,个人是蛮喜欢前端的,对js有自己的一些看法。但是并不能很好的定位自己的身份,还是鼓起蛮大的勇气打算写一些博客来和众位高手交流,个人作为尚未毕业的小白,希望大神不吝赐教。

废话不多,咱们来干货。

对于任何一门语言而言变量的解析规则将是决定语言质量和核心逻辑的关键,js也是如此。js中的变量尽管是松散类型,但是js变量拥有复杂的解析规则,但是在谈到变量解析规则之前我想我们有必要谈谈变量的组织结构。

执行环境在js中是相当重要的一个概念,执行环境定义了变量或者函数有权访问其他数据决定各自行为。但是执行环境往往作为一个高度抽象的描述而存在,尽管他拥有自己的数据结构用于描述自身,但是为了确定实际的具体行为我们还需要一个结构:变量对象,变量对象往往与执行环境相对应而存在,他用于保存环境中所有的变量和函数。当然这些对象一般来讲是不能被亵渎的,只有编译器这个king才能宠幸。不过很多书会讲到变量对象,也会提到执行环境,但是我一直不明白到底怎么产生一个执行环境?Js拥有三种代码类型:global、eval、function。个人认为只有这三种代码类型才能拥有执行环境。这一点我尚不能拿出令人信服的佐证,但是目前而言这种结论还是能解释得通,权且作为一种探讨模型,供大家探讨。

回归正题,我们继续讨论js数据组织结构,对于js而言我们首先进入的就是global这个执行环境,global是非常特殊的,当然依据语言的编译/解释到执行的大致规则而言,我们进入global之前编译器必须获得这个环境的相关描述,并且知道这个环境有什么能做什么,很明显这两个描述分别是执行环境和变量对象。Global的执行环境他拥有很抽象的描述,并且关联和负责init了具体做事的对象:变量对象,此对象拥有global的所有成员[js中函数和变量统称为成员有很本质的依据,之后会探讨],我们对应一段代码来看

<script>

1 function info () {

2 var message = "info function …";

3

4 returnglobalVar+ message;

5 }

6 console.log(info());

7 var globalVar ="global : ";

8 console.log(info());

</script>

这段代码非常简单,我们从头说起,当解释器解析页面时遇到了script标签则一次读取掉这个script块的代码,而后经过一系列的操作诸如语法检查、编译、初始化等操作之后呢确认没有error,则开始执行,当然首先进入的是global环境,在执行global之前编译器需要对global做一个入境的安检,这个安检详细到global穿什么内裤他都知道,当然这也无可厚非。这个安检初始化了一些描述信息:glboal的执行环境和变量对象,但是此步骤只会对声明进行处理,不会触发任何语句,globla的变量对象拥有两个成员:globalVar和info,前者是变量,后者是函数。Js中语句可以动态执行,而函数描述静态结构。解释器对二者处理也不尽相同,二者首先均被作为变量对象的成员而存在,但是变量初始化语句:globalVar ="global : ";在此时是不能被执行的,因为这是语句,语句尽管具有动态执行的特点,但是需要在安检之后,因为这个安检只能识别当前域中的所有声明,所以globlaVar的初始值是undefined,事实上这个处理将会导致很多很多的坑,因为此globalvar已经可用但却是undefined,之后兴许会讲。而info待遇则完全不同,info作为静态结构他的标识引用和代码段存在于不同的空间,函数声明的时候就会返回函数代码段的地址,然后和函数名关联,由于这种特殊的处理使得函数在这个安检的时候已经被关联了,所以你会发现即便函数在当前域的末尾声明,却在此域任何地方都是可用的。

安检完毕后global拥有了更多的自由,他可以完成自身可以完成的各项功能,于是他开始执行,js具有逐行执行的特点,但是静态结构不具有动态触发的特性,所以代码直接到6这一行,输出一个函数的返回值,info()告诉我们我们即将进入info函数的执行环境,此时info依然要做一次安检,因为这是一种新的代码类型,他拥有独立的执行环境,这点很重要,js中有些结构是没有独立的执行环境的,比如级块,他们只能依附生存。另一方面则独立执行环境的价值在于,本环境中的所有成员不能隶属于环境本身所在或者所依附的环境,具体来讲就是info内的成员是不能被global所安检的,尽管函数需要根植在globla下才能生存。其次这使得Function拥有足够的权限,某种程度上可以和global类比,所以呢info的安检和global就是十分类似了,但是函数作为十分特殊的存在拥有各种特殊的处理方式,函数执行环境对应的变量对象被表述为活动对象,并且这个活动对象和global的在诸多方面存在差异,我们暂且不谈。Info的活动对象只有message变量,安检完毕开始执行2完成info的初始化,然后执行4,许多语言返回基础类型都会返回值或者常量,既然需要返回值,则需要解析message和globalVar,怎么解析呢?很简单就是我要用message,我就在自己身上找不就完了,info函数的活动对象里有message这个成员,,这个操作在安检时完成。解析message轻而易举,但是更加复杂的问题来了,globalVar怎么办呢?info找遍全身上下也找不到,因为老子根本没有message这个东西好么?那怎么办呢?两种方案:1、我没有我就返回一个没有(undefined)。2.我虽然没有但是我的container可能会有,我可以试着申请。两种方式都可以,但很明显很少语言会采取第一种方式,虽然简单,也不容易出错,但是这样大大降低了语言能力范围,程序的模块交互式非常重要的操作,模块之间相互联系相互配合才能完成更加复杂的功能。但是单纯的合理性和为了语言的复杂性而使用方式二说服力不强,大多数语言采取这种变量解析方案的本质原因我认为在于语言结构,目前而言诸多语言采取单根模式来构造语言基础结构,单根很明显的一个特征就是对象继承自object或者其他根,正是由于单根才会有继承等一些语言特性,更重要的是单根往往伴随着一种复杂的数据结构:树,树所带来的复用特性和访问方式使得这样的变量解析变得合理和更容易操作与实现,单根的优点很多,暂时不做讨论,而是回到正题,既然采取后一种方式就会涉及一个问题:怎么申请呢?这就是变量跨执行环境解析的关键。无端端的跨环境解析是不可能的,二者必须建立联系,这种联系反映在数据结构上可以认为是树的父子节点迭代方式,而这个联系才是我们研究的猪脚:作用域链的构成与操作。

ok,今天到此为止,工作量略大,费神伤脑,期待明天的更新哦

程序员从来不是码农,一个专注于写代码而忽略了程序设计本身魅力的程序员永远不可能成长。如果你也认同我,同和我一起进步。我叫小胡,你准备好了么?

最美不过偷瞄你是你忽然转头,看见你的微笑

26857303的专栏

相关文章:

你感兴趣的文章:

标签云: