我在这里不说定义,找点问题,再解决问题。
一、原型
Q1:这样做输出的结果是什么?
jQuery= String; jQuery.prototype.say = function () { alert('呵呵'); }; var jj = new String(); jj.say();//String是否会有这种方法?
A1:运行之后我们发现,在JQuery中的修改导致了String对象原型的变更。所以我们可以得出结论,如果两个对象相等,那么它们会共用原型,一方进行操作,另一方也会因此改变。
Q2:比较一下上下两段代码有什么不同?
jQuery = function () { }; funcProto = function () { }; jQuery.prototype= funcProto; funcProto.say = function () { alert('呵呵'); }; var js = new jQuery(); js.say(); //---------------华丽的分割线---------------- funcProto = jQuery.prototype; funcProto.say = function () { alert('呵呵'); }; var js = new jQuery(); js.say();
A2:我们在运行之后就会发现,这二者没有什么区别。我们发现,原型不是一个只读的属性,是可读写的。
Q3:下面的代码有区别么?
jQuery = function () { }; funcProto = function () { }; jQuery.prototype.constructor = funcProto; funcProto.prototype.say = function () { alert('呵呵'); }; var js = new jQuery(); js.say();//只写constructor后会输出什么? //------------------------------------------ funcProto = jQuery.prototype.constructor; funcProto.prototype.say = function () { alert('呵呵'); }; var js = new jQuery(); js.say();//只读constructor后这又是啥?
A3:这时我们会发现区别:上面会报错,而下面却输出正常了。想必大家对constructor这个属性的含义并不陌生,通过这个实验我们可以认识到,原型的属性是可读写的,可是在只读和只写时出现了差别。所以我们要注意:在面向对象书写JavaScript的时候,有必要再写完后,重新再确认一次原型中的constructor的指向,否则有时会出现指向错误。为什么上半部分就会失败呢?接着往下看。
Q4:上个问题我们讨论了更改属性不能改变对象性质,那么我们试着去改变对象实例的Constructor的原型呢?
var jj = new String();
jj.constructor.prototype = Array.prototype;
alert(jj.constructor);
String.prototype = Array.prototype;
var jj = new String();
alert(jj.constructor);
A4:我们发现输出false,一个string类型的实例在改写了它的constructor的原型后并没有变成Array类型。而直接更改原型也不行,我们可以得知JavaScript规定,基本类型(Array String Number Function Object RegExp Date等JavaScript引擎中封装好的‘类’)的构造器的原型是只读的,不能赋值。
Q5:看看__proto__指针都指向什么?
alert(String.constructor.prototype === Array.constructor.prototype);//true alert(String.__proto__ === Array.__proto__);//true var str = ''; var arr = []; alert(str.__proto__); alert(arr.__proto__); str.__proto__ = arr.__proto__; alert(str.__proto__ === arr.__proto__);//false
A5:通过实验我们知道,__proto__指针其实就是constructor.prototype,下面的str.__proto__ = arr.__proto__操作是不是和Q4中的String.prototype=Array.prototype一样?所以我们得出结论,constructor.prototype属性是只读的。
现在我们应该能够知道Q3的问题所在,当我们在设置obj2.prototype.constructor=obj的时候却是可读写的,但是更改obj的prototype并不能回推到obj2,我们如果给obj和obj2判等,发现其实二者并不一样。因为obj2的实例的__proto__指针早已设定好指向obj2.prototype,所以Q3上半部分不能成功。而Q3下半部分之所以成功,是因为obj=obj2.prototype.constructor时,obj和obj2指针已经相等,所以改obj和改obj2是等效的。