视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
PrototypeClass对象学习_prototype
2020-11-27 20:43:32 责编:小采
文档


代码如下:
/* Based on Alex Arnell's inheritance implementation. */

var Class = (function() {
//临时存储parent的prototype
function subclass() {};

//创建类的方法
function create() {
var parent = null, properties = $A(arguments);
//检查新建一个类时,是否指定了一个父对象
//如果指定了父类,赋值给parent
if (Object.isFunction(properties[0]))
parent = properties.shift();

//真正用作返回的类,在创建实例时,将调用initialize方法进行初始化
function klass() {
this.initialize.apply(this, arguments);
}

//给klass添加addMethods方法,在调用create方法之后
//仍可以调用addMethods方法进行类级别的方法扩充
Object.extend(klass, Class.Methods);
//给返回的类添加两个属性,superclass:父类,subclasses:子类的集合
klass.superclass = parent;
klass.subclasses = [];

//如果创建类时指定了父对象,则把klass的原型指向父对象的实例,实现原型链继承
if (parent) {
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
//为父类添加子类,维护父类的子类集合
parent.subclasses.push(klass);
}

//向新类添加方法
for (var i = 0; i < properties.length; i++)
klass.addMethods(properties[i]);

//如果没有指定初始化方法,则默认把一个空方法赋给初始化方法
if (!klass.prototype.initialize)
klass.prototype.initialize = Prototype.emptyFunction;

/*
* 修正新类的构造函数,使得构造函数指向自己,这里特意说一下(如果注释掉下面这行):
* var Person=Class.create();
* var p1=new Person();
* alert(p1.constructor==Person) //true
* var Man=Class.create(Person)
* var m1=new Man();
* alert(m1.constrcutor==Man) //false
* alert(m1.constrcutor==Person) //true
* alert(m1.construcctor==p1.constrcutor) //true
*
* 看出问题来了吧?Man的构造函数竟然指向了Person的构造函数
* 问题的根源在klass.prototype = new subclass;这句话
* 具体原因我就不解释了,要详细理解的请查看《JavaScript语言精髓与编程实践》155~160页
*/
klass.prototype.constructor = klass;
return klass;
}

//把创建类时的方法添加到新类,或者在创建完类之后在添加类级别的方法
function addMethods(source) {
//取得新类的父类
var ancestor = this.superclass && this.superclass.prototype;
var properties = Object.keys(source);

//貌似下面的判断总是为真,不知道为什么这么写,知道的告诉我?
if (!Object.keys({ toString: true }).length) {
//如果新类重写了toString和valueOf方法则添加之
if (source.toString != Object.prototype.toString)
properties.push("toString");
if (source.valueOf != Object.prototype.valueOf)
properties.push("valueOf");
}

//遍历所有的新类声明中的方法
for (var i = 0, length = properties.length; i < length; i++) {
//property是函数名称,value是函数体
var property = properties[i], value = source[property];
//判断这个方法是否需要调用父类的同名方法
if (ancestor && Object.isFunction(value) &&
value.argumentNames().first() == "$super") {
var method = value;
//这里很重要!
//替换$super参数,使得这个参数指向父类的同名方法
//这里应用了Function的wrap方法,wrap方法的解释请参考【Prototype 学习——Function对象】
//method是新定义的方法,所以他的第一个参数为$super,然后从'='到'.'之间返回的是父类的同名方法
//最后调用wrap方法把$super参数替换成父类的同名方法,这样在子类调用$super()时,将调用父类的同名方法
//这里构造的非常棒!值得思考
value = (function(m) {
return function() { return ancestor[m].apply(this, arguments); };
})(property).wrap(method);

//将新产生的value(即经过修改过的子类方法)的valueOf和toString指向原子类的同名方法
//这里是在修正调用wrap方法之后的遗留问题
value.valueOf = method.valueOf.bind(method);
value.toString = method.toString.bind(method);
}
//把方法添加到新类中
this.prototype[property] = value;
}

return this;
}

//返回Class的可调用方法
return {
create: create,
Methods: {
addMethods: addMethods
}
};
})();

这个类就提供了2个方法:create和addMethods,上面的源码注释中已经说明的很清楚了,下面就看些例子,具体说明一下用法:
代码如下:
//声明Person类,并定义初始化方法
var Person = Class.create({
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
}
});

// when subclassing, specify the class you want to inherit from
var Pirate = Class.create(Person, {
// redefine the speak method
//注意这里的$super用法,在对照源码中的解释仔细看一下
say: function($super, message) {
return $super(message) + ', yarr!';
}
});

var john = new Pirate('Long John');
john.say('ahoy matey');
// -> "Long John: ahoy matey, yarr!"

代码如下:
var john = new Pirate('Long John');
john.sleep();
// -> ERROR: sleep is not a method
// every person should be able to sleep, not just pirates!

//这里是addMethods的用法,可以在类级别扩充方法
Person.addMethods({
sleep: function() {
return this.say('ZzZ');
}
});
john.sleep();

代码如下:
//这里是superclass和subclasses两个属性的用法

Person.superclass
// -> null
Person.subclasses.length
// -> 1
Person.subclasses.first() == Pirate
// -> true
Pirate.superclass == Person
// -> true

三个例子几本覆盖了Class类的方法,详细例子请参考:http://prototypejs.org/learn/class-inheritance

下载本文
显示全文
专题