JS虽然没有类的概念,但JS的灵活性可以让我们用各种办法去实现面向对象
关于继承的实现,应该有各种各样的办法
先抛个砖,这是我实现的办法之一
之前也有不同的办法实现过,但觉得这个办法更好些,而且代码很少
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
//扩展方法的定义,不得不污染一下 Function 了
Function.prototype.extend = function (base, ppt) {
var attr = null;
for (attr in base.prototype) {
//复制每个基类的prototype成员
this.prototype[attr] = base.prototype[attr];
} for (attr in ppt) {
if (this.prototype[attr] != null) {
//发现同名方法,重载
var fold = this.prototype[attr]; //旧方法
var fnew = ppt[attr]; //新的重载方法
fnew.base = fold; //附加base属性
this.prototype[attr] = fnew; //重载
}
else {
//添加
this.prototype[attr] = ppt[attr];
}
}
};
Function.base = "(arguments.callee.base.apply(this, arguments))"; //基类定义
function Base(name) {
this.name = name;
}
Base.prototype = {
getName: function () {
return this.name;
}
}; //扩展类1
function MyClass1(name) {
//调用父类构造方法
Base.call(this, name);
}
//扩展自Base类
MyClass1.extend(Base, {
//新的方法
showName: function () {
alert(this.getName());
},
//这个方法与父类同名,将被重载
getName: function () {
var name = eval(Function.base); //调用父类(Base)的同名方法
return name + "(MyClass1附加的信息)";
}
}); //扩展类2
function MyClass2(name) {
//调用父类构造方法
MyClass1.call(this, name);
}
MyClass2.extend(MyClass1, {
//再次重载
getName: function () {
var name = eval(Function.base); //调用父类(MyClass1)的同名方法
return name + "(MyClass2附加的信息)";
}
}); var inst = new MyClass2("MyClass2实例");
inst.showName();
</script>
</body>
</html>
如果有什么bug欢迎指出,如果有其它的办法实现,不妨贴出来讨论一下
关于继承的实现,应该有各种各样的办法
先抛个砖,这是我实现的办法之一
之前也有不同的办法实现过,但觉得这个办法更好些,而且代码很少
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
//扩展方法的定义,不得不污染一下 Function 了
Function.prototype.extend = function (base, ppt) {
var attr = null;
for (attr in base.prototype) {
//复制每个基类的prototype成员
this.prototype[attr] = base.prototype[attr];
} for (attr in ppt) {
if (this.prototype[attr] != null) {
//发现同名方法,重载
var fold = this.prototype[attr]; //旧方法
var fnew = ppt[attr]; //新的重载方法
fnew.base = fold; //附加base属性
this.prototype[attr] = fnew; //重载
}
else {
//添加
this.prototype[attr] = ppt[attr];
}
}
};
Function.base = "(arguments.callee.base.apply(this, arguments))"; //基类定义
function Base(name) {
this.name = name;
}
Base.prototype = {
getName: function () {
return this.name;
}
}; //扩展类1
function MyClass1(name) {
//调用父类构造方法
Base.call(this, name);
}
//扩展自Base类
MyClass1.extend(Base, {
//新的方法
showName: function () {
alert(this.getName());
},
//这个方法与父类同名,将被重载
getName: function () {
var name = eval(Function.base); //调用父类(Base)的同名方法
return name + "(MyClass1附加的信息)";
}
}); //扩展类2
function MyClass2(name) {
//调用父类构造方法
MyClass1.call(this, name);
}
MyClass2.extend(MyClass1, {
//再次重载
getName: function () {
var name = eval(Function.base); //调用父类(MyClass1)的同名方法
return name + "(MyClass2附加的信息)";
}
}); var inst = new MyClass2("MyClass2实例");
inst.showName();
</script>
</body>
</html>
如果有什么bug欢迎指出,如果有其它的办法实现,不妨贴出来讨论一下
var Class = {
extend:function(subClass,superClass){
var F = function(){};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
if(superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
/**
* 调用父类的构造函数
* @param subClass 子类函数名
* @param subInstance 子类对象引用
*/
,callSuper:function(subClass,subInstance){
var argsArr = [];
for(var i=2,len=arguments.length; i<len; i++) {
argsArr.push(arguments[i]);
}
subClass.superclass.constructor.apply(subInstance, argsArr);
}
/**
* 子类中调用父类的函数
* @param subClass 子类函数名
* @param subInstance 子类对象引用
* @param methodName 父类方法名
*/
,runSuperMethod:function(subClass,subInstance,methodName) {
return subClass.superclass[methodName].call(subInstance);
}};// Demo
// 声明父类
var Person = function(param){
this.name = param.name;
this.age = param.age;
}
Person.prototype.sayName = function(){
alert("My name is " + this.name);
}
Person.prototype.sayAge = function(){
alert("My age is " + this.age);
}
Person.prototype.getAge = function(){
return this.age;
}
// 声明子类
var Man = function(param){
// 调用父类的构造函数
Class.callSuper(Man,this,param);
}
// 继承父类
Class.extend(Man,Person);// 覆盖父类的sayAge方法
Man.prototype.sayAge = function(){
alert(this.name + "'s age is " + this.age);
}
// 覆盖父类的方法,并且调用父类原来的方法
Man.prototype.getAge = function(){
// 先调用父类方法返回年龄
var age = Class.runSuperMethod(Man,this,'getAge');
// 年龄+1
alert(this.name + "'s age is " + (age + 1));
}
// 测试
var man = new Man({name:"Jim",age:22});
man.sayName(); // 这里调用父类的方法
man.sayAge(); // 这里调用自己的方法
man.getAge();
</script>
详见:YUI-extend
{
this.x = 1;
}function Sub()
{
Base.call(this);
}
最方便
createClass:function(c,p){
var C=p?c:(c&&c.isFunction())?c:(c&&c.constructor).isFunction()?c.constructor:function(){};
if(!p)delete c.constructor;else delete p.constructor;
C.prototype=C.prototype||{};
C.prototype.copy(p?p:c);
C.prototype.constructor=C;
try{return C}catch(ex){}finally{c=p=C=null}
},
extend:function(sub,sup,p){
sup=sup||{};
if(sup && sup.isObject()){
var oc=Object.prototype.constructor;
p=sup;
sup=sub;
sub=p.constructor==oc?function(){arguments.callee.superclass.apply(this,arguments)}:p.constructor;
oc=null;
}
if(sup.prototype.constructor!=sup)sup.prototype.constructor=sup;
var F=function(){};F.prototype=sup.prototype;
var tmp=sub.prototype;
if(sub.superclass){
sub.prototype=tmp;
sub.prototype.copyIf(new F(),true);
sub.prototype.copy(p);
}
else{
sub.prototype=new F();
sub.prototype.copy(tmp);
sub.prototype.copy(p);
sub.superclass=sup;
}
sub.prototype.constructor=sub;
try{return sub}catch(ex){}finally{F=tmp=sup=sub=p=null}
}
};目测1 3楼都没实现
光靠目测是没用的,跑一把吧alert(man instanceof Person) // true
alert(man instanceof Man) // true
// First we check if the user passed in just the superClass with overrides
if (Ext.isObject(superclass)) {
overrides = superclass;
superclass = subclass;
subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
superclass.apply(this, arguments);
};
} //<debug>
if (!superclass) {
Ext.Error.raise({
sourceClass: 'Ext',
sourceMethod: 'extend',
msg: 'Attempting to extend from a class which has not been loaded on the page.'
});
}
//</debug> // We create a new temporary class
var F = function() {},
subclassProto, superclassProto = superclass.prototype; F.prototype = superclassProto;
subclassProto = subclass.prototype = new F();
subclassProto.constructor = subclass;
subclass.superclass = superclassProto; if (superclassProto.constructor === objectConstructor) {
superclassProto.constructor = superclass;
} subclass.override = function(overrides) {
Ext.override(subclass, overrides);
}; subclassProto.override = inlineOverrides;
subclassProto.proto = subclassProto; subclass.override(overrides);
subclass.extend = function(o) {
return Ext.extend(subclass, o);
}; return subclass;
};
而我的方案中并不去理会这个 constructor,会存在什么风险吗?
var sub=function(){};
sub.prototype=new base();//原型方式扩展
var t1=new sub();
alert(t1 instanceof base);//弹出true为实现那个constructor主要是在今后很方便,通过一个实例可以获取它的构造类,加上superclass可以获取父类的构造类。
不是,instanceof判断一个对象是否是一个类的实例,具体机制不好解释,跟原型链有关,而那个constructor是获取一个对象的构造器或构造函数:var a={};//a=1 a=false a='a' a=new Date() a=Math a=/ /g ……
alert(a.constructor)
var classA=function(){}
a=new classA();
alert(a.constructor===classA);
alert(classA.prototype.constructor===classA);在函数扩展中对constructor的控制很重要,以9楼中的那个例子:var base=function(){};
var sub=function(){};
sub.prototype=new base();//原型方式扩展
var t1=new sub();
alert(t1.constructor===base);
/**
* 这里表示对象t1的构造器为base而不是sub(原型扩展方式的缺陷,而extjs yui的扩展方式都是这个方式),
* 因为sub的原型被指向了base的一个实例,而任意一个base实例都有一个constructor属性,该属性指向base,所以sub的原型中就有一个指向base的constructor属性,即:sub.prototype.constructor=base
alert(sub.prototype.constructor===base);
*/所以在你想要实现js中的继承时需要考虑如下要点:以base为父类 sub为子类 ob为父类实例 os为子类实例
1.ob isA base
2.os isA sub
3.os isA base
4.ob.constructor===base
5.os.constructor===sub以上5点为必要的,前三点通过原型链的继承方式可以实现,后两点需要在继承后人为地指定各自的构造器。至于superlcass,实现sub.superlcass===base,这个根据自己的需要,方便今后使用。extjs是把子类的superclass设置为了父类的prototype,方便寻找父类的静态(公共)方法和属性,即sub.superclass=base.prototype
{
this.color = sColor;
this.sayColor = function() {
alert(this.color);
}
}
function ClassB(sColor)
{
this.newMethod = ClassA;
this.newMethod(sColor);
delete this.newMethod;
}