JavaScript是一个解释型语言
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( "函数声明" ) }
}
第三阶段:函数内部的变量提升
AO : {
arguments: <ArgO>,
c: true,
a: function a(){},
b: function b(){ console.log( "函数声明" ) },
d: undefined
}
函数内部又定义了变量 var c和var a,当变量提升时,发现AO中已经存在a和c属性,如果变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性。如果不相同切不存在,那就会放到AO中,值为undefined。
当上面的这些准备工作做完之后,才会开始执行函数内部的代码,这样就很好明白,函数内部的变量,在什么阶段分别代表什么样的值!
闭包解析
在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、函数fnSon
AO:{
a:1,
fnSon: function(){}
}
此时的fnSon被赋值给了fnTest,那么foo方法的AO在执行完之后就没办法被销毁,当fnTest被调用的时候,代码执行完之后,foo的AO对象中的a变成了2,再次调用fnTest的时候就变成3。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。