var A = function(){
var name = null;
this.setName = function(_name){
name = _name;
}
}
var B = function(){
A.call(this); //相当于super(),A是B的父类
this.setName = function(_name){
//这里想调用父类的setName
alert("this is class B");
}
}
extends(B, A); //继承原型链
在这个代码里,非常纠结,为了让name成为私有变量,使用了闭包的办法,但是后果就是setName函数只能写到this里,而不能写到原型链里,所以在子类B的setName函数里想要调用A里的setName函数就杯具了。
怎么破?
然后setName只是简单调用_setName然后子类调用父类的方法也是调用_setName
var A = function(){
var _name = null;
this._setName = function(name){
_name = name;
}
this._getName = function(){
return _name;
}
}
A.prototype.setName = function(name){
this._setName(name);
}
A.prototype.getName = function(){
return this._getName();
}
var B = function(){
var _sex;
A.call(this);
}
qq.html.extend(B, A);
B.prototype.setName = function(name){
A.prototype.setName.call(this, name);
}
var b = new B();
b.setName("aaa");
alert(b.getName());
<html>
<head>
<title></title>
<script type="text/javascript" language="javascript">
/************************/
/* 类继承机制的简单实现 */
/************************/
(function () {
function BaseRef() {
this.members = {};
this.memberPoint = {};
}
BaseRef.prototype = (function () {
function addMember(name, mb) {
var baseMember = null;
if (this.members[name] != null) {
baseMember = this.members[name];
}
this.members[name] = { method: mb, base: baseMember };
}
function clone() {
var newRef = new BaseRef();
for (var attr in this.members) {
newRef.members[attr] = this.members[attr];
}
return newRef;
}
return {
addMember: addMember,
clone: clone
};
})(); function callBase() {
var funName = arguments[0];
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
var br = this._base;
var point = br.memberPoint[funName];
if (point == null) {
point = br.members[funName];
}
var fun = point.method;
br.memberPoint[funName] = point.base;
try {
fun.apply(this, args);
}
catch (err) { alert(err); }
br.memberPoint[funName] = point;
} Function.prototype.Extend = function (baseCls, proto) {
for (var attr in baseCls.prototype) {
//复制基类的prototype
if (attr == "_base") {
this.prototype[attr] = baseCls.prototype[attr].clone();
continue;
}
this.prototype[attr] = baseCls.prototype[attr];
}
for (var attr in proto) {
if (this.prototype[attr] != null) {
//出现同名成员,作重载操作处理
var oldMember = this.prototype[attr];
if (this.prototype["_base"] == null) {
this.prototype["_base"] = new BaseRef();
}
var br = this.prototype["_base"];
br.addMember(attr, oldMember);
}
this.prototype[attr] = proto[attr];
}
this.prototype.callBase = callBase;
}
})();
</script>
<script type="text/javascript" language="javascript">
//基类
function Cls0(){
this.name="这是基类";
}
Cls0.prototype={
ShowMe:function(){
alert(this.name);
}
};
//子类
function Cls1(){
//调用父类构造函数
Cls0.call(this);
this.name+="(子类添加的内容)";
}
Cls1.Extend(Cls0,{
ShowMe:function(){
alert("即将调用父类方法");
this.callBase("ShowMe");
}
});
var inst=new Cls1();
inst.ShowMe();
</script>
</head>
<body>
</body>
</html>
var Div = function(){
this.width = 0;
this.height = 0;
this.dom = document.createElement("div");
}而你设置width和height的时候,不光要改变width和height的变量,还得修改dom的style,所以你不能允许用户直接new Div().width = 45,因为这样dom对象的style并没有被修改,所以我们需要用闭包把width对象保护起来,而不能放到this里。所以需要一个wapper来setWidth,而不是直接修改width属性,这就是私有变量。接下来我需要扩展DIV类, 里面除了这个div之外,还有另外一个重叠的div,现在setWidth需要做三件事,1:设置width变量,2:设置第一个div的style,3:设置第二个div的style,前两个都可以通过调用父类的setWidth实现,而第三个则需要调用父类的setWidth之后再进行设置。
这就是java,c++等语言最常用的情况了。
这个例子有些傻,但是实际中有很多这种需要,不要说width和height每次从style里去读,第一是性能,第二是canvas的变换矩阵只能自己计算,保存一个变量,而不能从CanvasContext里去取
//相当于super(),A是B的父类
A.call(this);
//这时候this.setName已经存在,你再这样写是覆盖了继承过来的setName
this.setName = function(_name){
//这里想调用父类的setName
alert("this is class B");
}
}
就是说父类的方法为了保存私有变量,是在构造函数定义到this里的,所以子类继承的方式不是继承prototype里的属性。
而是在实例化对象的时候,在构造函数里通过apply或者call修改this指针调用父类的构造函数。而这一步必须放到构造函数的最开头,因为后面自定义的函数可能会调用这些继承的函数。这个时候根本无法知道是否有函数重名
var A = function(){
var name = null;
this.setName = function(_name){
name = _name;
}
}为什么要用这种方式来定义setName而不用prototype呢?虽然运行效果是一样的,但这种方式相当于每创建一个实例,就会产生一段相同的代码 function(_name){ name = _name; },但prototype的话,不管是多少个实例,都会使用同一个function
var name = null;
this._setName = function(_name){
name = _name;
}
}
A.prototype={
setName:function(name){
this._setName(name);
}
}这样如何?然后子类继承setName。虽然多了一层,但似乎能解决你的问题
这就是我3楼的方案啊,目前我能想到最靠谱的就是这个,当然,如果追求完美的话有2个缺点:
1。 基类比较丑,多了一层调用,多了一层性能开销
2。 无法阻止子类直接调用_setName,如果在setName里判断caller名称不是setName就报异常的话大部分情况多了一层判断,感觉有点亏
var name = null;
this.setName = function(_name){
name = _name;
alert("in class a");
}
this.getName = function(){
return name;
}
}
var B = function(){
this.setName = function setName(_name){
var proto = this.constructor.prototype;
proto[arguments.callee.name](_name);
alert("in class b");
}
}
B.prototype = new A();
B.prototype.constructor = B;
var b = new B();
b.setName("bbb");
alert(b.getName());
OOP框架:Fan v1.3.70 完全模拟java的面向对象编程
/**
* Fan
*
* @version 1.3.70
*
* @author FuFan
*
* @date 2011/11/10
*
* OOP部分使用范例:
*
*/
// [创建接口]
Fan.interface('Fan.test.IA', function(){
this.INFO = 'Fan.test.IA';
this.showA = Function;
});
Fan.interface('Fan.test.IB', function(){
this.INFO = 'Fan.test.IB';
this.showB = Function;
});
// [接口继承]
Fan.interface('Fan.test.IC', Fan.test.IB, Fan.test.IA, function(){
this.INFO = 'Fan.test.IC';
this.showC = Function;
});
// [创建类] 默认继承Object
Fan.clazz('Fan.test.DImpl', function(){
var _d;
this.DImpl = function(d){
this.$super();
_d = d;
};
this.showA = function(){
return _d;
};
});
// [类继承]
Fan.clazz('Fan.test.EImpl', Fan.test.DImpl, function(){
//alert('2:' + cfg);
this.a = null;
this.b = null;
this.c = null;
this.EImpl = function(cfg){
this.$super(cfg.d); // 带参数调用父类构造方法
this.a = 'EImpl.a';
this.b = cfg.b;
this.c = cfg.c;
};
this.showA = function(){
return this.a;
};
});
// [类继承+实现接口]
Fan.clazz('Fan.test.FImpl', Fan.test.EImpl, Fan.test.IC, Fan.test.IB,fnction(){
this.a = 'FImpl.a';
this.FImpl = function(cfg){
this.$super(cfg);
};
this.showA = function(){
return this.a;
};
this.showB = function(){
return this.b;
};
this.showC = function(){
return this.c;
};
this.showF = function(){
return 'Fan.test.FImpl';
};
});
// [使用]
f = new Fan.test.FImpl({a:'aa', b:'bb', c:'cc', d:'dd'});
Logger.info('f.showA() == ' + f.showA());
if(f.showA() == 'FImpl.a'){
Logger.info('子类调用正常');
} else {
Logger.error('子类调用异常');
}
// [类型鉴别]
if(f instanceof Fan.test.FImpl
&& f instanceof Fan.test.EImpl
&& f instanceof Fan.test.DImpl
&& f instanceof Object
&& f.$super instanceof Fan.test.EImpl
&& Fan.instance(f, Fan.test.IA)
&& Fan.instance(f, Fan.test.IB)
&& Fan.instance(f, Fan.test.IC)) {
Logger.info('类型鉴别正常');
}
else{
Logger.error('类型鉴别异常');
}
// [父类句柄]
Logger.info('f.$super.showA() == ' + f.$super.showA());
Logger.info('f.$super.$super.showA() == ' + f.$super.$super.showA());
if(f.$super.showA() == 'EImpl.a' && f.$super.$super.showA() == 'dd'){
Logger.info('父类调用正常');
} else {
Logger.error('父类调用异常');
}