Prototype 学习——Class对象

Prototype’s object for class-based OOP.

prototype OOP编程的基础,详细说明一下源码:

  1. /* Based on Alex Arnell's inheritance implementation. */
  2. var Class = (function() {
  3. //临时存储parent的prototype
  4. function subclass() {};
  5. //创建类的方法
  6. function create() {
  7. var parent = null, properties = $A(arguments);
  8. //检查新建一个类时,是否指定了一个父对象
  9. //如果指定了父类,赋值给parent
  10. if (Object.isFunction(properties[0]))
  11. parent = properties.shift();
  12. //真正用作返回的类,在创建实例时,将调用initialize方法进行初始化
  13. function klass() {
  14. this.initialize.apply(this, arguments);
  15. }
  16. //给klass添加addMethods方法,在调用create方法之后
  17. //仍可以调用addMethods方法进行类级别的方法扩充
  18. Object.extend(klass, Class.Methods);
  19. //给返回的类添加两个属性,superclass:父类,subclasses:子类的集合
  20. klass.superclass = parent;
  21. klass.subclasses = [];
  22. //如果创建类时指定了父对象,则把klass的原型指向父对象的实例,实现原型链继承
  23. if (parent) {
  24. subclass.prototype = parent.prototype;
  25. klass.prototype = new subclass;
  26. //为父类添加子类,维护父类的子类集合
  27. parent.subclasses.push(klass);
  28. }
  29. //向新类添加方法
  30. for (var i = 0; i < properties.length; i++)
  31. klass.addMethods(properties[i]);
  32. //如果没有指定初始化方法,则默认把一个空方法赋给初始化方法
  33. if (!klass.prototype.initialize)
  34. klass.prototype.initialize = Prototype.emptyFunction;
  35. /*
  36. * 修正新类的构造函数,使得构造函数指向自己,这里特意说一下(如果注释掉下面这行):
  37. * var Person=Class.create();
  38. * var p1=new Person();
  39. * alert(p1.constructor==Person) //true
  40. * var Man=Class.create(Person)
  41. * var m1=new Man();
  42. * alert(m1.constrcutor==Man) //false
  43. * alert(m1.constrcutor==Person) //true
  44. * alert(m1.construcctor==p1.constrcutor) //true
  45. *
  46. * 看出问题来了吧?Man的构造函数竟然指向了Person的构造函数
  47. * 问题的根源在klass.prototype = new subclass;这句话
  48. * 具体原因我就不解释了,要详细理解的请查看《JavaScript语言精髓与编程实践》155~160页
  49. */
  50. klass.prototype.constructor = klass;
  51. return klass;
  52. }
  53. //把创建类时的方法添加到新类,或者在创建完类之后在添加类级别的方法
  54. function addMethods(source) {
  55. //取得新类的父类
  56. var ancestor = this.superclass && this.superclass.prototype;
  57. var properties = Object.keys(source);
  58. //貌似下面的判断总是为真,不知道为什么这么写,知道的告诉我?
  59. if (!Object.keys({ toString: true }).length) {
  60. //如果新类重写了toString和valueOf方法则添加之
  61. if (source.toString != Object.prototype.toString)
  62. properties.push("toString");
  63. if (source.valueOf != Object.prototype.valueOf)
  64. properties.push("valueOf");
  65. }
  66. //遍历所有的新类声明中的方法
  67. for (var i = 0, length = properties.length; i < length; i++) {
  68. //property是函数名称,value是函数体
  69. var property = properties[i], value = source[property];
  70. //判断这个方法是否需要调用父类的同名方法
  71. if (ancestor && Object.isFunction(value) &&
  72. value.argumentNames().first() == "$super") {
  73. var method = value;
  74. //这里很重要!
  75. //替换$super参数,使得这个参数指向父类的同名方法
  76. //这里应用了Function的wrap方法,wrap方法的解释请参考【Prototype 学习——Function对象】
  77. //method是新定义的方法,所以他的第一个参数为$super,然后从'='到'.'之间返回的是父类的同名方法
  78. //最后调用wrap方法把$super参数替换成父类的同名方法,这样在子类调用$super()时,将调用父类的同名方法
  79. //这里构造的非常棒!值得思考
  80. value = (function(m) {
  81. return function() { return ancestor[m].apply(this, arguments); };
  82. })(property).wrap(method);
  83. //将新产生的value(即经过修改过的子类方法)的valueOf和toString指向原子类的同名方法
  84. //这里是在修正调用wrap方法之后的遗留问题
  85. value.valueOf = method.valueOf.bind(method);
  86. value.toString = method.toString.bind(method);
  87. }
  88. //把方法添加到新类中
  89. this.prototype[property] = value;
  90. }
  91. return this;
  92. }
  93. //返回Class的可调用方法
  94. return {
  95. create: create,
  96. Methods: {
  97. addMethods: addMethods
  98. }
  99. };
  100. })();

这个类就提供了2个方法:create和addMethods,上面的源码注释中已经说明的很清楚了,下面就看些例子,具体说明一下用法:

  1. //声明Person类,并定义初始化方法
  2. var Person = Class.create({
  3. initialize: function(name) {
  4. this.name = name;
  5. },
  6. say: function(message) {
  7. return this.name + ': ' + message;
  8. }
  9. });
  10. // when subclassing, specify the class you want to inherit from
  11. var Pirate = Class.create(Person, {
  12. // redefine the speak method
  13. //注意这里的$super用法,在对照源码中的解释仔细看一下
  14. say: function($super, message) {
  15. return $super(message) + ', yarr!';
  16. }
  17. });
  18. var john = new Pirate('Long John');
  19. john.say('ahoy matey');
  20. // -> "Long John: ahoy matey, yarr!"

  1. var john = new Pirate('Long John');
  2. john.sleep();
  3. // -> ERROR: sleep is not a method
  4. // every person should be able to sleep, not just pirates!
  5. //这里是addMethods的用法,可以在类级别扩充方法
  6. Person.addMethods({
  7. sleep: function() {
  8. return this.say('ZzZ');
  9. }
  10. });
  11. john.sleep();

  1. //这里是superclass和subclasses两个属性的用法
  2. Person.superclass
  3. // -> null
  4. Person.subclasses.length
  5. // -> 1
  6. Person.subclasses.first() == Pirate
  7. // -> true
  8. Pirate.superclass == Person
  9. // -> true

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

posted @ 2009-07-29 16:46  麦飞  阅读(326)  评论(0编辑  收藏  举报