您的位置:首页 > Web前端 > JavaScript

解析JS的prototype继承机制

2011-04-28 17:17 357 查看
许多人一直对JS的prototype继承机制不明了,到底在创建一个类的实例的时候,解析器为我们做了些什么呢?
首先,我们来看一个例子:

function class1() {

this.name = "my name";

}

function class2() {

this.age = 123;

}

class2.prototype = new class1();

var obj = new class2();

alert(obj.name);

alert(class2.prototype.name);

delete class2.prototype;

alert(obj.name);

alert(class2.prototype);

alert(class2.prototype.name);


结果将是
firefox “my name” “my name” “my name” “[object object]” undefined
IE “my name” “my name” “my name” undefined 出错

从最后两个结果来看,Firefox下的prototype是可以删除的,但它却是一定会存在的,在做delete(class2.prototype)的时候,Firefox将prototype变成一个普通的Object。
而IE对此的处理方式有所不同,当删除class2.prototype的时候,它就真真正正被删掉了,所以会得到undefined,并且最后一行会出错。
可能就有人会有疑问了,我们都已经把class2.prototype给删除了,虽然Firefox和IE处理方式不同,但确确实实肯定不会存在class2.prototype.name这个变量了,但为什么在删除之后,class2的实例obj的name值会存在?这就是我们要说的重点之一了。

接着看下边几行代码,请使用Firefox来运行。

function class1() {

this.name = "my name";

}

function class2() {

this.age = 123;

}

class2.prototype = new class1();

var obj = new class2();

alert(obj.name);

alert(obj.__proto__.name);

delete class2.prototype;

alert(obj.name);

alert(obj.__proto__.name);

obj.name = "new name";

alert(obj.name);

alert(obj.__proto__.name);

delete obj.name

alert(obj.name);

alert(obj.__proto__.name);


在我们指定的firefox下运行结果是: “my name” “my name” “my name” “my name” “new name” “my name” “my name” “my name”
是不是觉得结果好奇怪?__proto__这又是什么变量呢?为什么在delete(obj.name)之后,原先这个值为”new name”的属性没消失,但却随着这行代码变成了”my name”
稍加分析,其实这个__proto__对象,就是原先那个class2.prototype,而且尽管class2.prototype被清掉了,这个obj.__proto__对象却依然存在!
我们立刻就可以想到,JS里一个类的实例在实例化完毕之后,就与原先的类的关系断开了。当它在本身找不着一个属性的时候,会尝试去__proto__里找,如果找着就把它当成本身的属性了。
这是根据Firefox提供出来的这个__proto__对象推断出来的,那IE又是怎么样的呢?我们继续看下边简化了的代码:

function class1() {

this.name = "my name";

}

function class2() {

this.age = 123;

}

class2.prototype = new class1();

var obj = new class2();

alert(obj.name);

alert(obj.__proto__);

delete class2.prototype;

alert(obj.name);

obj.name = "new name";

alert(obj.name);

delete obj.name

alert(obj.name);


在看过Firefox下的运行结果后,我们可以很欣喜地看到IE其实处理方式应该是一致的,在删除obj.name之后,它的值确实像Firefox一样,”new name”变成了”my name”,但它并没有给我们提供__proto__这样的对象。

于是,我很肯定但有点武断地得出了以下推论:

在运行”new xxx()”的时候,解析器会创建一个空的Object,然后为它创建了一个名字可能为__proto__(为什么要用可能二字?因为IE不知道起的是什么名,但Firefox确实用了这个名字)的属性,然后将xxx类的prototype赋值给它。接下来,进入类本身,相当于xxx.call(obj)的方式把新的对象当成this一行一行执行下去,然后返回该对象。
从这里也可以看出JS里根本没有类这种东西,或者说没有真正的类,它纯属模拟出来的,这也是为什么类的定义跟函数的定义都用了function这个关键词,事实上类的定义就是一个函数,它负责将传进来的this对象根据函数的逻辑给它增加了属性以及方法,跟其它高级语言里的类的定义是完全不一样的。

欢迎回贴指出我的不足之处,讨论讨论
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: