ECMAScript5面向类的编程探讨
基于代码优雅和简洁的考虑,本人一直在探究如何在es5里面写出类似于Java那样面向对象的代码,下面是一些代码与大家分享一下,里面有详细的注释说明,如有疑问,可以评论区留言。
在函数原型绑定一个方法,工具函数
/*
-
在函数原型里绑定方法
-
*/
Function.prototype.method = function (name, func) {
if (!this.prototype.hasOwnProperty(name)) {
this.prototype[name] = func;
}
};
工具函数,对象继承,在后面的类式继承里使用
/*
*工具函数:对象继承
*@param son:表示儿子对象
*@param parent:表示父亲对象
*@return 新的儿子对象
*/
function extend(son,parent)
{
/*为了让新对象复制儿子对象中已有的属性,我们需要改造son
*使其具有这种形式:{a:属性描述符对象,b:属性描述符对象}
*注意
Object.getOwnPropertyNames(son)返回所有自有(非继承)属性,包括不可枚举的
*/
var names = Object.getOwnPropertyNames(son);
var obj={};//复制son的临时对象
for (var i = 0; i < names.length; i++) {
obj[names[i]]=Object.getOwnPropertyDescriptor(son, names[i]);
}
//创建新的对象,以parent作为原型
return Object.create(parent,obj);
}
类式继承,参数可以是对象或者构造函数,对象表示一个接口
/*
-
定义:extend,用于类继承
-
参数:父类型,可以是对象或者构造函数
-
返回值:升级版的子类,比如:A'=A.extend(B);
-
*/
Function.prototype.extend = function (parent) {
if(this._super)
{
throw new Error("超类已经存在,不可重复继承!");
}
var Parent = parent || Object;
//父类是个object
if(typeof Parent==="object")
{
//临时函数
var F=function(){};
F.prototype=Parent;
F.prototype.constructor=F;
Parent=F;
}
if (typeof Parent === 'function') {
//生成升级版的子类构造函数
var prototype=extend(this.prototype,Parent.prototype);
//保存父类的原型
Object.defineProperty(this,"_super",{
value:Parent.prototype,
writable:true,
enumerable:false,
configurable:false
});
//修改原型的constructor属性,为Child
prototype.constructor = this;
this.prototype = prototype;
return this;
} else {
throw new TypeError('参数:' + p + '类型不合法!');
}
};
测试代码如下:
var Person=function(name){
this.name=name;
Person.method("getName",function(){return this.name;});
};
注意:原型方法的定义在构造函数里面。这样会导致原型方法延迟绑定,也就是在实例化的时候才能绑定到原型中。
var Student=function Student(name,age){
/*这里会自动调用Person的构造函数,等同于:Person.call(this,name),缺陷是要保证参数的正确顺序
*/
this.age=age;
Student.method("getAge",function(){return this.age;});
}.extend(Person);
//实例化
new Student("张三",34).getName();
new Person("李四").getName();
这种风格的代码优点有如下几条
1,简洁优雅。
2,原型方法直到实例化时才绑定到原型,当然,也可以按常规的方式在构造函数外面定义,继承调用前和调用后都可以。
3,如果把原型方法定义放在构造函数里面,整个类的定义更紧凑,都在一对花括号里面。
4,可以继承接口,父类如果是对象,可以视为一个无构造函数的抽象接口。
5,构造函数调用时先调用父类构造函数。