作用域链:
JS代码需要运行在一个环境当中,这个环境称为执行上下文(execution context),执行上下文可以认为是一个对象。
执行上下文中定义的变量,都会保存在与之关联的变量对象(variable object)中。当执行上下文中的所有代码执行完毕后,该执行上下文将销毁。
执行上下文分为全局执行上下文和函数执行上下文。Script脚本的执行上下文就是全局上下文,而函数执行时会创建自己的执行上下文。
JS的作用域是变量或函数定义的地方。比如函数内定义了一个变量,那么这个变量在这个函数内部可以被访问到。
执行上下文创建的时候,一方面会关联变量对象,一方面还会创建一个作用域链(Scope chain)。作用域链可以认为是一个数组,里面放着一系列的变量对象。
某个执行上下文的作用域链的第一项保存的是该执行上下文自己的变量对象,第二项则是父级执行上下文的变量对象,第n项如此类推,直到全局执行上下文。
某个执行上下文中,要访问某一个变量的时候,会从该执行上下文的作用域链的第一项开始找,直到找到全局执行上下文。如果找到了返回,如果没有找到那么就抛出ReferenceError。
可以看到变量的查找,是在一个链中去进行的。
原型链:
JS也是一门面向对象语言。对象之间继承的机制是原型继承,这些继承形成的链成为原型链。
当访问对象的某个属性是,该对象实例本身没有该属性,则在其指向的原型上去找,如果还找不到,则在原型的原型上去找。如果找到了返回,找不到就抛出ReferenceError。
基于原型链的继承,需要使用一些阻隔的手段解决污染的问题,这里不探讨。
依赖链:
函数需要访问的变量或数据,都是其依赖。A函数访问B函数,B函数访问C函数,这种依赖关系形成了依赖链。
不同函数之间,虽然没有直接的相互调用关系,却依赖了相同的数据,那么他们彼此之间依然有链的关系。
调用链:
调用链是我们讨论的重点。程序运行的本质就是不停的调用,那么底层就是不断的计算。不管软件的功能看上去多复杂,都可以归结于是调用。