函数对象
首先,大家得明确一个概念:函数就是对象,代表函数的对象就是函数对象。既然是对象,那它又是被谁构造出来的呢?下面我们来看一段描述:javascript代码中定义函数,或者调用function创建函数时,最终都会以类似这样的形式调用function函数:var newfun=function(funargs, funbody); 。由此可知函数对象是由function这个函数对象构造出来的。
注:function对象本身也是一个函数,因此它也一个函数对象。关于function的深入理解,请见后续博文。
正面我们来看一段代码:
复制代码 代码如下:
//定义方式一
function func(x) {
alert(x);
}
//定义方式二
var func = function(x) {
alert(x);
};
//实际执行
var func = new function(“x”, “alert(x);”);
通过上面的代码可知,函数func无非是由function对象接收两个参数后构造出来的而矣!
注:关于定义方式一与定义方式二的区别,请见后续博文
函数对象的创建过程
函数对象详细创建步骤如下:
1. 创建一个build-in object对象fn
2. 将fn的内部[[prototype]]设为function.prototype
3. 设置内部的[[call]]属性,它是内部实现的一个方法,处理函数调用的逻辑。(简单的理解为调用函数体)
4. 设置内部的[[construct]]属性,它是内部实现的一个方法,处理逻辑参考对象创建过程。(简单的理解为创建对象《理解javascript_06_理解对象的创建过程》一文)
5. 设置fn.length为funargs.length,如果函数没有参数,则将fn.length设置为0
6. 使用new object()同样的逻辑创建一个object对象fnproto
7. 将fnproto.constructor设为fn
8. 将fn.prototype设为fnproto
9. 返回fn
步骤1跟步骤6的区别为,步骤1只是创建内部用来实现object对象的数据结构(build-in object structure),并完成内部必要的初始化工作,但它的[[prototype]]、[[call]]、[[construct]]等属性应当为 null或者内部初始化值,即我们可以理解为不指向任何对象(对[[prototype]]这样的属性而言),或者不包含任何处理(对 [[call]]、[[construct]]这样的方法而言)。步骤6则将按照《理解javascript_06_理解对象的创建过程》创建一个新的对象,它的 [[prototype]]等被设置了。
从上面的处理步骤可以了解,任何时候我们定义一个函数,它的prototype是一个object实例,这样默认情况下我们创建自定义函数的实例对象时,它们的prototype链将指向object.prototype。
注:function一个特殊的地方,是它的[[call]]和[[construct]]处理逻辑一样。深层次的原因将在后续博文中介绍。
下面我们写一些用例脚本来测试一下上面的理论:
复制代码 代码如下:
function animal(){
}
alert(animal.length);//0
var dog = new animal();
这个js证明了步骤5的正确性。最后,还是来看一下函数对象的内存图,简单起见,内存图只描述了animal的构造过程:
来自于一个整体的分析图:
图片本身已经能解释很多很多的问题了,结合前面instanceof原理,对象构造原理,原型链原理,自已去体会吧,我就不多说什么了。
其实上function对象是一个很奇妙的对象,它与object的关系更是扑朔迷离,我将在《理解javascript_09_function与object》中解释这一切。
最后的声明:理论过于复杂,我不改保证其正确性。但经过多方的测试,还未发现理论与实际冲突的地方。