JS里的对象在Ajax发展之后, 就跟着疯狂起来, 要玩好JS的对象, 就要搞清楚构造器(constructor), 指针(pointer), 原型(prototype)
这篇文章主要记录我对prototype的理解
prototype
最初的用法是, 为了避免方法在构造器里随机数据被实例化时而产生重复的副本
后来被用在"继承"上面了, 注意, JS语义上是没有继承的, 这里说的是人为的实现
总结, prototype其实也是指针, 默认是实例的指针, 当然也可以人为的改变,
父类A, 子类B
默认情况, B.prototype=A.prototype
这样, B可以访问A的所有原型方法, 这时, B的构造器也变成A了
改变一下, B.prototype=A
这样, B可以访问A的所有静态方法, 这时, B的构造器也变成类A的指针->类的指针->Function的指针->Function的构造器
以下是实例验证
严重注意以上代码的备注, 是new之后的instance的指针, 不是Class的指针,
下面改一下代码验证一下
然后, 当执行到b.showName();时, 就会抛出异常了, 因为 showName是prototype方法, 是指定在A的实例指针下的, 给A添加方法pointer()以获取实例的指针, 然后把它赋予B.prototype
以上代码运行正常, 证明了prototype实质上就是指于实例的指针
那么, 如果, 把prototype的指针指于类, 又会如何呢, 我的想法是, 会得到类的静态方法或属性
以下代码, 给A添加静态方法showSex和静态属性city, 然后把A的类,
结果应该是A的原型方法showName会报错, 而b.showSex和alert(b.city)会得到正确的执行
代码执行正常, 验证无误
再检验一下constructor
结果表明
alert(b.constructor), 连 B 的构造器都变成 A 的了
alert(b.constructor==A), 再比较一次, 输出true, 没有悬念了
继续挖掘, 把B.prototype=A, 即把A的类指针赋予B的prototype
结果表明, B.prototype指到类A的指针去了, 而类的指针, 又指向类的构造器了
再看看A, 被B"继承"后的样子, 在B.prototype=A的时候, this就已经是指向A了, showAge是不是也应该存在于A的实例呢? 在做个实验, 一个是A被继承前, 一个是A被继承后
结果为:
1: undefined
2: function showAge(){...}
3: undefined
4: function showAge(){...}
5: 518000
6: 518000
可以看出, expend之前之后的A, 其实已经是一样了,
undefined, 是因为没有给变量赋值, 但函数指针已经正确指到B的showAge了
关于prototype也是, 对于a, 在被B继承后, 也可以获取了518000了, 用java语言来说, prototype只是实例指针而已, 而不论showAge还是post, 都是一个对象, 所以当a的指针指向这个"后来"加上的对象时, 当然也就可以得到518000了
但这样的话, B被继承A之后, A也得到了B的prototype了, 对于继承机制来说, 这样还算是继承吗? A和B的区别, 仅仅是静态方法和属性而已
这篇文章主要记录我对prototype的理解
prototype
最初的用法是, 为了避免方法在构造器里随机数据被实例化时而产生重复的副本
后来被用在"继承"上面了, 注意, JS语义上是没有继承的, 这里说的是人为的实现
总结, prototype其实也是指针, 默认是实例的指针, 当然也可以人为的改变,
父类A, 子类B
默认情况, B.prototype=A.prototype
这样, B可以访问A的所有原型方法, 这时, B的构造器也变成A了
改变一下, B.prototype=A
这样, B可以访问A的所有静态方法, 这时, B的构造器也变成类A的指针->类的指针->Function的指针->Function的构造器
以下是实例验证
function demo(){
var A=function(name){
this.name=name;
}
A.prototype.showName=function(){alert(this.name);}
var B=function(name, age){
A.call(this, name);
this.age=age;
}
//B.prototype=new A(); //这里2行代码的效果是一样的
B.prototype=A.prototype; //目的是返回A的"实例"的指针
B.prototype.showAge=function(){alert(this.age);}
var b=new B("david", 31);
b.showName();
b.showAge();
}
严重注意以上代码的备注, 是new之后的instance的指针, 不是Class的指针,
下面改一下代码验证一下
var A=function(name){
this.name=name;
//return this; 这是隐式代码, JS会自动帮我们执行, 这里是关键
}
改为
var A=function(name){
var o=new Object();
o.name=name;
return o;
}
然后, 当执行到b.showName();时, 就会抛出异常了, 因为 showName是prototype方法, 是指定在A的实例指针下的, 给A添加方法pointer()以获取实例的指针, 然后把它赋予B.prototype
function demo(){
var A=function(name){
this.name=name;
}
A.prototype.showName=function(){alert(this.name);} //the function return this, "this" is the pointer of instance
A.prototype.pointer=function(){return this;}
var B=function(name, age){
A.call(this, name);
this.age=age;
}
//B.prototype=new A();
//B.prototype=A.prototype;
B.prototype=new A().pointer();
B.prototype.showAge=function(){alert(this.age);}
var b=new B("david", 31);
b.showName();
b.showAge();
}
以上代码运行正常, 证明了prototype实质上就是指于实例的指针
那么, 如果, 把prototype的指针指于类, 又会如何呢, 我的想法是, 会得到类的静态方法或属性
以下代码, 给A添加静态方法showSex和静态属性city, 然后把A的类,
结果应该是A的原型方法showName会报错, 而b.showSex和alert(b.city)会得到正确的执行
function demo(){
var A=function(name){
this.name=name;
}
A.prototype.showName=function(){alert(this.name);} //the function return this, "this" is the pointer of instance
A.prototype.pointer=function(){return this;}
A.showSex=function(){alert("male");}
A.city="shenzhen";
var B=function(name, age){
A.call(this, name);
this.age=age;
}
//B.prototype=new A();
//B.prototype=A.prototype;
B.prototype=A;
B.prototype.showAge=function(){alert(this.age);}
var b=new B("david", 31);
try {
b.showName();
} catch (exception) {
alert(exception);
}
b.showAge();
b.showSex();
alert(b.city);
}
代码执行正常, 验证无误
再检验一下constructor
function demo(){
var A=function(name){
this.name=name;
}
A.prototype.showName=function(){alert(this.name);} //the function return this, "this" is the pointer of instance
A.prototype.showSex=function(){alert("male");}
A.prototype.city="shenzhen";
var B=function(name, age){
A.call(this, name);
this.age=age;
}
B.prototype=A.prototype;
B.prototype.showAge=function(){alert(this.age);}
var b=new B("david", 31);
try {
alert(b.constructor); //output Class A construct
alert(b.constructor==A);//output true
} catch (exception) {
alert(exception);
}
}
结果表明
alert(b.constructor), 连 B 的构造器都变成 A 的了
alert(b.constructor==A), 再比较一次, 输出true, 没有悬念了
继续挖掘, 把B.prototype=A, 即把A的类指针赋予B的prototype
function demo(){
var A=function(name){
this.name=name;
}
A.prototype.showName=function(){alert(this.name);} //the function return this, "this" is the pointer of instance
A.prototype.showSex=function(){alert("male");}
A.prototype.city="shenzhen";
var B=function(name, age){
A.call(this, name);
this.age=age;
}
B.prototype=A;
B.prototype.showAge=function(){alert(this.age);}
var b=new B("david", 31);
try {
alert(b.constructor==Function.constructor);//output true
alert(b.constructor); //output Function's constructor
} catch (exception) {
alert(exception);
}
}
结果表明, B.prototype指到类A的指针去了, 而类的指针, 又指向类的构造器了
再看看A, 被B"继承"后的样子, 在B.prototype=A的时候, this就已经是指向A了, showAge是不是也应该存在于A的实例呢? 在做个实验, 一个是A被继承前, 一个是A被继承后
function demo(){
var A=function(name){
this.name=name;
}
A.prototype.showName=function(){alert(this.name);} //the function return this, "this" is the pointer of instance
A.prototype.showSex=function(){alert("male");}
A.prototype.city="shenzhen";
var a=new A("mochacoffee");
var B=function(name, age){
A.call(this, name);
this.age=age;
}
B.prototype=A.prototype;
B.prototype.showAge=function(){alert(this.age);}
B.prototype.post="518000"; //add property for test
var c=new A("reno");
a.showAge(); //*1
alert(a.showAge); //*2
c.showAge(); //*3
alert(c.showAge); //*4
alert(a.post); //*5
alert(c.post); //*6
}
结果为:
1: undefined
2: function showAge(){...}
3: undefined
4: function showAge(){...}
5: 518000
6: 518000
可以看出, expend之前之后的A, 其实已经是一样了,
undefined, 是因为没有给变量赋值, 但函数指针已经正确指到B的showAge了
关于prototype也是, 对于a, 在被B继承后, 也可以获取了518000了, 用java语言来说, prototype只是实例指针而已, 而不论showAge还是post, 都是一个对象, 所以当a的指针指向这个"后来"加上的对象时, 当然也就可以得到518000了
但这样的话, B被继承A之后, A也得到了B的prototype了, 对于继承机制来说, 这样还算是继承吗? A和B的区别, 仅仅是静态方法和属性而已