日期:2014-05-16  浏览次数:20426 次

【原】关于JS中的原型prototype

最近一直在看书。上班看。下班看。

关于原型一直不懂。

有的地方说是简单的复制。有的地方说是引用。

现在结合本人自己的理解以及测试的代码,给大家解释一下。

(如有说错。请大侠指出。看官别拍砖哈~~)

?

代码如下:

<script>
function a(){
  
}
a.prototype.sayHi = function(temp){
  alert(temp+" say HI")
}
function b(){

}
b.prototype = a.prototype;//为了证明prototype的赋值(b继承a)是复制(大家理解为复制,会好理解点。)
var A = new a;
A.sayHi("a");//调用sayHi方法。结果是a say HI
var B = new b;
B.sayHi("b")//调用sayHi方法。结果是b say HI(说明调用的方法一致)

A.sayHi = function(){
  alert("Hello world!")
}//大家应该都了解prototype的机制。会在原型链向上顺藤摸瓜到第一个方法。这里,我的目的就是改变当前对象的sayHi方法的引用(就是指向一个新的同名方法)。但是,原型链中的sayHi方法没变化。如果变化了,那么下面B.sayHi()肯定会跟随变化的。但事实却没有变化。
A.sayHi("a");//调用sayHi方法。结果是"Hello world
B.sayHi("b")//调用sayHi方法。结果是b say HI(说明调用的方法一致,证明了prototype的赋值(b继承a)的确是一个个的复制字面量)

a.prototype.goodbye = function(temp){
  alert(temp+" GoodBye");
}//这里,我在a类的原型链中晚绑定一个新方法。(记住JS的晚绑定机制!)
A.goodbye("a");//调用goodbye方法。结果是a GoodBye
B.goodbye("b");//调用goodbye方法。结果是b GoodBye(JS的晚绑定特性!!)
</script>

?

代码中的注释,我都是说的复制。

其实。JS中的对象包括Object和Function都是引用类型。

那为什么说是复制呢?

因为在第一次重写原型链中的sayHi方法的时候,是让A对象的sayHi方法重新引用到一个新的对象上。可是B对象的sayHi方法还是引用的内存中的原先的sayHi方法。这就是JS中鼎鼎大名的reference 。所以,代码中说的复制,其实更确切的说,应该是复制引用(我给这个机制起名为:references copy )!还是结合我的代码。其实2个sayHi方法都存在内存中,只是2个对象的指向不同而已。A的sayHi已经指向了新的改变了的方法,而B的还是指向原来的那个方法。这就想String类型的道理是一样的。

?

备注:

代码中的继承。我写的是b.prototype = a.prototype;

【备注:(这里是我后来看FF的监控,才知道的,上下两段代码是有区别的。感谢一位博友的指正。)】

请区别于b.prototype = new b;(js区别于java的特性还有:实例化类对象时,如果不传递参数,则可以省略括号。)

?

好了。就先解释这么多,本人的理解也有限。不到之处,请多多指正。

?

?

?

1 楼 maoquan0515 2011-03-25  
LZ举例不当导致理解错误!
请先理解下
b.prototype = a.prototype;  和

b.prototype = new a();的区别。

如果b.prototype = a.prototype,那么a的静态方法a.sayHi(区别于原型上的方法)是不会影响到b的,
对b.sayHi的调用过程是b.sayHi  --> b.prototype.sayHi(即 a.prototype.sayHi)--> ....

如果是b.prototype = new a();的话,
那么a.sayHi方法就在b的原型链上,

对b.sayHi的调用过程是b.sayHi--> b.prototype.sayHi --> a.sayHi(实例化的对象a) --> a.prototype.sayHi

PS:最好将构造函数名大写,对象名小写。



2 楼 北极的。鱼 2011-03-25  
maoquan0515 写道
LZ举例不当导致理解错误!
请先理解下
b.prototype = a.prototype;  和

b.prototype = new a();的区别。

如果b.prototype = a.prototype,那么a的静态方法a.sayHi(区别于原型上的方法)是不会影响到b的,
对b.sayHi的调用过程是b.sayHi  --> b.prototype.sayHi(即 a.prototype.sayHi)--> ....

如果是b.prototype = new a();的话,
那么a.sayHi方法就在b的原型链上,
对b.sayHi的调用过程是b.sayHi--> b.prototype.sayHi --> a.sayHi(实例化的对象a) --> a.prototype.sayHi



PS:最好将构造函数名大写,对象名小写。







楼上的。
请问你自己测试过代码吗?
我标记为红色的部分。
一个类的静态方法可以被这个类的实例调用吗?
连这个类自己的实例都不能访问的静态方法。
继承了这个类的类的实例又怎么能访问??
建议你仔细思考下。
||这里是重点,我们知道对象调用方法时首先检查实例方法,如果实例方法不存在,再去查找原型链,实例方法存在,直接调用实例方法。,前面A实现了sayHi的实例方法,所以直接输出18行的Hello world!,而不会再去原型链查找。而B方法仍然会去调用A的原型上的方法。这里如果将11行的b.prototype = a.prototype;改为b.prototype = new a();即b的原型为a的一个实例,那么17行重写a的实例方法sayHi 将会对B.sayHi("b")产生影响,请LZ调试!
  22.  
  23. a.prototype.goodbye = function(temp){ 
  24.   alert(temp+" GoodBye"); 
  25. }//这里,我在a类的原型链中晚绑定一个新方法。(记住JS的晚绑定机制!) 
  26. A.goodbye("a");//调用goodbye方法。结果是a GoodBye 
  27. B.goodbye("b");//调用goodby