执行上下文与作用域链
执行上下文(简称为上下文)决定 了JS执行过程中可以获得哪些变量、函数、数据,一段程序可能被分割成许多不同的上下文,每一个上下文都会绑定一个变量对象,它就像一个容器,用来存当前上下文所有已定义或可获取的变量、函数等,位于最顶部或最外层的上下文称为全局上下文,全局上下文在浏览器里由window代理,在nodejs里是global。
需要注意的是,上下文和作用域(scope)是不同的概念,JS本身是单线程 的,每当有function被执行时,就会产生一个新的上下文,这一上下文会被压入JS的上下文堆栈中,function执行结束后则被弹出,因此JS解释器总是在栈顶上下文中执行,在生成新的上下文时,首先会绑定该上下文的变量对象,其中包括arguments和这个函数中定义的变量,之后会创建属于这个上下文的作用域链,最后把this赋给这一function所属的对象。
在function被执行时生成新的上下文时会先绑定当前上下文的变量对象,再创建作用域链,我们知道function的定义是可以嵌套在其他function所创建的上下文中,也可以并列地定义在同一个上下文中,作用域链实际上就是自下而上的将所有嵌套定义的上下文所绑定的变量对象串接在一起,使嵌套的function可以嵌套上层上下文的变量,而并列的function之间互不干扰。
闭包
如果理解了上文中提到的上下文与作用域链的机制,再来看闭包的概念就很清楚了,每个function在调用时会创建新的上下文及作用域链,而作用域链就是将外层上下文所绑定的变量对象逐一串连起来,使当前的function可以获取外层上下文的变量、数据等。如果我们在function中定义新的function,同时将内层function作为值返回,那么内层function所包含的作用域将会一起返回,即使内层function在其他上下文中执行,其内部的作用域链仍然保持原有的数据,而当前的上下文可能无法获取原生外层function中的数据,使用function内部的作用域被,从而形成闭包。
我们知道,在JS中一切都是对象(Objet),但是js中并没有类,js是基于原型,但并不是所有的对象都拥有prototype这个属性:
var a = {}; console.log(a.prototype);//undefined var b = function(){}; console.log(b.prototype); // => {} var c = "hello"; console.log(c.prototype); //undefined