函数具有两个功能,一个是声明创建功能,在声明时就创建了一个函数对象,另一个是运行功能,在函数体内进行逻辑操作.
首先看下面的例子:
function Fn(){console.log("Fn")};
Fn();
第一句是函数的声明时,第二句是函数运行时.function类型的对象比object类型的对象多了个运行时.那么我们来了解一下这两个时间里,函数做了什么?
函数在声明时: 创建了一个函数对象(作为当前所在的函数对象的OA对象的属性,这句的理解要看完运行时),并且为这个函数对象添加了一些隐含的属性对象,
1,__proto__,指向它的原型,默认指向Function.prototype,而Function.prototype.__proto__ 指向 Object.prototype;
2.prototype.这是作为它创建出来的实例对象的原型来存在的,其中也默认protoype.constructor == 函数名 ,
3.length:形参的个数,
4.scope对象(无法访问),可以认为是栈结构(后进先出),把函数声明时所在函数对象的VO对象引用入栈顶
还有其它的一些隐含对象,我没有研究.
函数在运行时:
1,动态指定this,可以通过a.fb(),call,apply,bind等方式指定,如果是new的话,则this指向{},但如果没有指定this,则this.的指向global对象(注意this不能通过this = a这样的方式赋值)
2.创建实参对象arguments,此对象类似数组,存储实参值.
3,创建AO对象(活动对象),且其所以的函数对象的scope指这OA对象的引用放入栈顶,如果有实参,按内部变量处理,并且引用arguments,按顺序赋值.函数内var声明的对象(初始值为undefined)或者function 声明的对象(此时担声明的函数对象也创建出来,其标识符指向报创建出来的函数对象);所以var a = function(){};和 function a(){}在这时的处理是不同的,var方式 a 的初始值为undefined,等运行到这句时才创建函数对象,并且a指向刚创建的函数对象,而function a(){}方式是还没有运行到这句,已经创建函数对象,并且 a 指向这函数对象.
4.开始按顺序执行,若有取值,则在当前的函数的scope中查找(作用域查找机制,对象的属性值按原型链查找),直找到global对象(scope最底的OA对象),再查找到globa的原型Object.prototype如果没有找到则取值为undefined. 如果执行到return ,若不指明return 值,则返回this指向的对象.所以new操作就是刚开始把this指向{},默认返回this指向的对象,有return 对象,则返回指定对象.得到的实例对像的__proto__值指向函数对象的prototype对象,用函数对象的prototype的constructor来指实例对象的实例类型.函数返回时:清理战场工作,如果返回对象中没有引用到的对象,则交由GC处理,如果返回对象有对此对象的引用,这样的对象则不能被清理,
看懂下面的例子,就知道什么是作用域链和闭包了:
function Fn (){ //!.
//3
var b =4; //4
function Fb(){
//9
b = b+6; //10
console.log(b); //11
}
var Fc = function (){//5
//13
b = b-2; //14
console.log(b); //15
}
return {fb: Fb,fc: Fc}//.6
}
var fn = Fn(); //2 //7
fn.fb(); //8
fn.fc(); //12
看到所标的号,表示执行顺序.
1.Fn函数声明时,此时Fn的scope有全局OA对象,并且Fn作为此全局OA对象的属性,Fn.__proto__==Function.prototype
2.Fn函数运行时,进入函数体,创建Fn的OA对象,指定this为global,并且为Fn的scope添加Fn的OA对象,此时Fn的scope有全局OA和Fn的OA
3.创建函数内var和function声明的对象,var声明的值为undefined,funtion声明的则创建函数对象,并且为所创建的函数对象创建它的OA对象.在这一步中,就可以得到 b = undefined;Fb=[Function]; Fc = undefined;注意Fb和Fc的差别.此时Fb已经是声明创建时了,那么会为Fb对象创建Fb的scope对象,并且把Fn的scope对象传给Fb的scope对象,那么这时的Fb的scope里也有全局OA和Fn的OA
4.b = 4;
5.此时才进入Fc的声明创建时,其创建情况参照Fb的创建,得到Fc=[Function]
6.创建{fb: Fb,fc: Fc}对象,并且返回此对象
7.将返回的{fb: Fb,fc: Fc}赋值给fn
8.进入Fb函数运行时,创建Fb的OA对象,并把Fb的OA对象放入到Fb的spoce中,那么现在Fb的scope中有全局OA,Fn的OA和Fb的OA.this指定为fn,
9.处理var和function声明,但Fb函数内没有,所以这里没有作什么处理.
10.在作用域链中找b,首先在Fb的OA上找,没有找到b,那住上找,在Fn的OA中找到b,此时的b值 为4,所以进行运算,得到b=10,
11.输出10
12.类似第8步
13.类似第9步
14.类似第10步,首先在Fc的OA上找,没有找到b,那住上找,在Fn的OA中找到b,此时的b值10,所以进行运算,得到b=8,
15.输出8
理解好上面的过程,就很容易理解作用域链和闭包了.所谓闭包就是返回结果里含有函数OA的引用,造成函数OA不能被清理,所以OA里声明的变量也不能被清理,并且保存了状态.