解析JS的prototype继承机制

许多人一直对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对象根据函数的逻辑给它增加了属性以及方法,跟其它高级语言里的类的定义是完全不一样的。

 

原文:http://bbs.51js.com/thread-83874-1-1.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值