MDN上明确的说,JavaScript是一个轻量级的、解释型的、面向对象的、将函数视为一级公民的语言。
那么,既然js是一个解释型语言,那它就是在运行时把代码转换成机器能够识别的语言。哪它又为何会存在变量提高呢?
下面这篇文章给出了解释,在此也特别感谢做者的分享!
https://mp.weixin.qq.com/s/ne...数组
function fn(c){ console.log(c); //true var c = false; console.log(a); //function a(){} var a = 1; console.log(a); //1 function a(){ }; console.log(a); //1 b(); //函数声明 var b = function(){ console.log("函数表达式"); } function b(){ console.log( "函数声明" ) } b(); //函数表达式 var d = 4; } fn(true);
上面这个fn方法很简单,相信不少人都能过作出来,但确定也不少人不理解结果为何是这样!
那么这个过程是怎样执行的呢:
首先,js在执行前会产生一个GO(Global Object),也就是咱们常说的全局做用域。当一个方法被调用的时候会造成一个局部做用域AO(Activation Object)。
全局代码在执行的时候,先是变量提高,在全局做用域内添加属性,而后是函数(以函数声明建立的函数)提高,再是代码执行。
函数在被调用的时候,以上面的fn这个方法为例,进入函数上下文,可是在执行代码以前,经历的阶段:
第一阶段:首先建立一个AO,并包含下列属性:闭包
AO : { arguments: <ArgO>, //函数内部参数的类数组对象 c: true, //传入的参数,若是没有传递实参,那么值就是undefined }
第二阶段:函数内部的函数(以函数声明建立的函数)提高函数
AO : { arguments: <ArgO>, c: true, a: function a(){}, b: function b(){ console.log( "函数声明" ) } }
第三阶段:函数内部的变量提高code
AO : { arguments: <ArgO>, c: true, a: function a(){}, b: function b(){ console.log( "函数声明" ) }, d: undefined }
函数内部又定义了变量 var c和var a,当变量提高时,发现AO中已经存在a和c属性,若是变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性。若是不相同切不存在,那就会放到AO中,值为undefined。对象
当上面的这些准备工做作完以后,才会开始执行函数内部的代码,这样就很好明白,函数内部的变量,在什么阶段分别表明什么样的值!ip
在JavaScript高级程序3中,对闭包的描述是这样的,闭包是指有权访问另外一个函数做用域中的变量的函数。那么,很显然,闭包其实就是一个函数。
那么咱们怎样经过GO、AO理解闭包呢:作用域
function foo(){ var a = 1; function fnSon(){ a++; console.log(a); } return fnSon; } var fnTest = foo(); fnTest(); //2 fnTest(); //3
当foo这个方法被调用的时候,建立一个AO,当函数执行完以后AO里面包含了变量a、函数fnSonget
AO:{ a:1, fnSon: function(){} }
此时的fnSon被赋值给了fnTest,那么foo方法的AO在执行完以后就没办法被销毁,当fnTest被调用的时候,代码执行完以后,foo的AO对象中的a变成了2,再次调用fnTest的时候就变成3。io