读书人

【原】关于JS中的原形prototype

发布时间: 2012-10-10 13:58:11 作者: rapoo

【原】关于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 HIvar 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 worldB.sayHi("b")//调用sayHi方法。结果是b say HI(说明调用的方法一致,证明了prototype的赋值(b继承a)的确是一个个的复制字面量)a.prototype.goodbye = function(temp){  alert(temp+" GoodBye");}//这里,我在a类的原型链中晚绑定一个新方法。(记住JS的晚绑定机制!)A.goodbye("a");//调用goodbye方法。结果是a GoodByeB.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的特性还有:实例化类对象时,如果不传递参数,则可以省略括号。)

?

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

?

?

?

25. }//这里,我在a类的原型链中晚绑定一个新方法。(记住JS的晚绑定机制!)
26. A.goodbye("a");//调用goodbye方法。结果是a GoodBye
27. B.goodbye("b");//调用goodbye方法。结果是b GoodBye(JS的晚绑定特性!!)
||如前面所述,由于B调用的是a的原型链,所以对a原型链的修改会影响到B,这是JS的惰性绑定没有问题
28. </script> 7. }
8. function b(){
9.
10. }
11. b.prototype = a.prototype;//为了证明prototype的赋值(b继承a)是复制(大家理解为复制,会好理解点。) ||这里b的原型直接指向了a的原型,而不是指向a的具体对象
12. var A = new a;
13. A.sayHi("a");//调用sayHi方法。结果是a say HI
14. var B = new b;
15. B.sayHi("b")//调用sayHi方法。结果是b say HI(说明调用的方法一致)
16. ||上面两个方法A.sayHi("a");和 B.sayHi("b")其实均调用了a.prototype上的方法

17. A.sayHi = function(){
18. alert("Hello world!")
19. }// 大家应该都了解prototype的机制。会在原型链向上顺藤摸瓜到第一个方法。这里,我的目的就是改变当前对象的sayHi方法的引用(就是指向一个新的同名方法)。但是,原型链中的sayHi方法没变化。如果变化了,那么下面B.sayHi()肯定会跟随变化的。但事实却没有变化。 ||这里重写了A的实例方法sayHi

20. A.sayHi("a");//调用sayHi方法。结果是"Hello world
21. B.sayHi("b")//调用sayHi方法。结果是b say HI(说明调用的方法一致,证明了prototype的赋值(b继承a)的确是一个个的复制字面量)

}
function b(){

}
b.prototype =A; //对比 b.prototype = a.prototype!!

A = new a();
B = new b();

A.sayHi = function(){
alert("Hello world!")
}

B.sayHi();}
function b(){

}
b.prototype =A; //对比 b.prototype = a.prototype!!

A = new a();
B = new b();

A.sayHi = function(){
alert("Hello world!")
}

B.sayHi();



=====================================
我很高兴你这么专业。
不过,希望楼上的兄弟放出代码前,自己先测试下。
我清楚你想表达的。代码如下:
<script>
function a(){
}
a.prototype.sayHi = function(temp){
alert(temp+" say HI")
}
A = new a();
function b(){
}
b.prototype =A;
B = new b();
A.sayHi = function(){
alert("Hello world!")
}
B.sayHi();
</script>

首先。我要说明一下。
你的代码运行达到了你的预期效果。
即,调用B.sayHi();改变了a.prototype中定义的sayHi方法了。
可是这不能说明是改变了原型中的sayHi。
B中调用这个方法只是搜索到A(a的实例)中的的静态方法,就停止搜索了。
仔细想想,是不是这样的?
为了证明这一点,我写了如下代码。(仅仅是在最后添加了一个c。绿色标记出)
function a(){
}
a.prototype.sayHi = function(temp){
alert(temp+" say HI")
}
A = new a();
function b(){
}
b.prototype =A;
B = new b();
A.sayHi = function(){
alert("Hello world!")
}
B.sayHi();
var c = new a;
c.sayHi("c")

结果显而易见。
证明了其实原型链中的sayHi方法被没有被重写。
简言之,还是返回到JS中的原型链机制。一个方法被调用的时候,只是顺藤摸瓜搜索第一个同名的方法。如你说的,先搜自己的静态成员,然后是自己的prototype。然后是父类的静态成员,然后是父类的prototype。如此顺藤摸瓜上去,知道Object的prototype为止!我在原文中给这个机制起了个名字叫references copy。
可是,实质是怎么样的呢?当一个类或实例重新设置同名的方法的时候,其实是把这个类或实例的这个属性指向新的引用了。原来的prototype中的同名的方法并没有被冲掉。
希望能对你有帮助。}
function b(){

}
b.prototype =A; //对比 b.prototype = a.prototype!!

A = new a();
B = new b();

A.sayHi = function(){
alert("Hello world!")
}

B.sayHi();


我很高兴你这么专业。
不过,希望你在提交代码前,先自己运行下代码。正确了再提交。
看我绿色处。
首先你把一个对象赋给了b类的原型。正确,可以这么做。(不过,请记得在实例化A以后!!)
然后请问这和b的复制云云的有什么关系????b仍然指向a的原型,无论a的实例方法写成什么对原型都没有影响,因为b总是执行a.prototype.sayHi。

你的文章中有些地方需斟酌:
1.
请问这和b的复制云云的有什么关系????b仍然指向a的原型,无论a的实例方法写成什么对原型都没有影响,因为b总是执行a.prototype.sayHi。

你的文章中有些地方需斟酌:
1.
引用代码中的继承。我写的是b.prototype = a.prototype;

其实还可以写成b.prototype = new b;

你认为这两个一样吗??

2.
引用简言之,还是返回到JS中的原型链机制。一个方法被调用的时候,
只是顺藤摸瓜搜索第一个同名的方法。如你说的,先搜自己的静态成员,
然后是自己的prototype。然后是父类的静态成员,然后是父类的prototype。

静态方法、实例方法、原型方法你搞清楚了吗???原型链中会搜索静态方法吗?

3.

b.prototype =A; //对比 b.prototype = a.prototype!!

我写这两个的对比只是想告诉你,如果你使用b.prototype = a.prototype实现b继承a的话,你对a实例方法的修改将不会影响到b的任何方法,除非你改变a原型方法,这样会影响到b。而你使用b.prototype =A的话,对具体实例A的修改则会影响到b,仅此而已。

4.这里的大小写真的搞的我头晕,具体实例用大写,构造函数用小写,楼主需要专业一点。

5.这篇文章错误百出,“顶”的人可能就楼主一个吧??

6。结束,不来了,怎么撞到这里来的,晕死。



首先。请你审视下,你现在的论点和原先的不一样。
原先,你想表明父类的原型里的内容是可以被改变的。(看你的例子。)
现在,你却又说父类的原型里的内容不能被改变。
你真的看懂我的意思吗?请你仔细看看我的原文。
总结1: b.prototype=a.prototype;
b.prototype=A;//这2种继承的区别你研究过吗?我说的b的实例调用方法的时候会有一个搜索父类的静态同名方法的过程,特指的是子类的prototype是父类的一个实例的情况下。如果子类的prototype是父类的prototype,另当别论!(我举的这个例子,你真的看懂了吗?!!)
总结2: 你一直强调是子类的方法是覆盖!(请看你自己的评论!)
我给你写的最后一段代码,已经证明了,只是引用重新定向而已。事实说明一切。而你自己也知道你的解释站不住。还在一个劲的指责别人的理论。(我放出的代码全是运行过的!你的呢?!我不修改,根本无法运行!我不是指责你,只是想说,请你放出代码前自己先测试。)你一直问,复制是什么意思,我在博文里说了很清楚了,是引用复制!OK?!你还不理解,就指责错误。和你说了这么多,真浪费时间!!

读书人网 >JavaScript

热点推荐