虚度人生

导航

奇妙的Function和prototype

先来看一段代码

function fn() {};
Function.prototype.test = 'fn';
fn.prototype.test = 'aaa';
var fo = new fn();
alert(fo.test);

相信所有人都知道答案,ok,再来一段:

function fn() { return {}; };
Function.prototype.test = 'fn';
fn.prototype.test = 'aaa';
var fo = new fn();
alert(fo.test);

可能有一部分人被淘汰了,答案是undefined,再来一段:

function fn() { return fn; };
Function.prototype.test = 'fn';
fn.prototype.test = 'aaa';
var fo = new fn();
alert(fo.test);

是什么? 很不幸,'fn',又有一些被淘汰了,那我们继续往前:

function fn() { alert(this.test); return {test: 'bbb'}; };
fn.prototype.test = 'aaa';
var fo = new fn();

结果是'aaa'。很有一部分人冲到了最后,不过,有人能清楚的解释一下,这是为什么呢? 相信绝大多数同学黯然的低下了头。

正当我们为广大劳苦大众发愁的时候,一声春雷响,我们迎来了@richie同学的JavaScript对象模型-执行模型。该文洋洋洒洒,图文并茂的讲述了具体的执行机制,这年头,能如此较真的人还真不多,赞一个。

 

摘录精华如下:

对象创建过程:

是指形如new Fn(args)的过程

1. 创建一个build-in object对象obj并初始化
2. 如果Fn.prototype是Object类型,则将obj的内部[[Prototype]]设置为Fn.prototype,否则obj的[[Prototype]]将为其初始化值(即Object.prototype)
3. 将obj作为this,使用args参数调用Fn的内部[[Call]]方法
    3.1 内部[[Call]]方法创建当前执行上下文
    3.2 调用Fn的函数体
    3.3 销毁当前的执行上下文
    3.4 返回Fn函数体的返回值,如果F的函数体没有返回值则返回undefined
4. 如果[[Call]]的返回值是Object类型,则返回这个值,否则返回obj
注意步骤2中, prototype指对象显示的prototype属性,而[[Prototype]]则代表对象内部Prototype属性(隐式的)。

Firefox中,可以用__proto__获取[[Prototype]]。

 

函数对象创建过程:

 JavaScript代码中定义函数,或者调用Function创建函数时,最终都会以类似这样的形式调用Function函数:var newFun=Function(funArgs, funBody); 。创建函数对象的主要步骤如下:
1. 创建一个build-in object对象fn
2. 将fn的内部[[Prototype]]设为Function.prototype
3. 设置内部的[[Call]]属性,它是内部实现的一个方法,处理逻辑参考对象创建过程的步骤3
4. 设置内部的[[Construct]]属性,它是内部实现的一个方法,处理逻辑参考对象创建过程的步骤1,2,3,4
5. 设置fn.length为funArgs.length,如果函数没有参数,则将fn.length设置为0
6. 使用new Object()同样的逻辑创建一个Object对象fnProto
7. 将fnProto.constructor设为fn
8. 将fn.prototype设为fnProto
9. 返回fn

 

压轴的模型图:

红色虚线表示[[Prototype]]

posted on 2010-02-22 09:55  nozer0  阅读(587)  评论(0编辑  收藏  举报