Prototype Class对象学习


Posted in Javascript onJuly 19, 2009
/* 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

Javascript 相关文章推荐
extjs 学习笔记(二) Ext.Element类
Oct 13 Javascript
ExtJs Excel导出并下载IIS服务器端遇到的问题
Sep 16 Javascript
使用jQuery同时控制四张图片的伸缩实现代码
Apr 19 Javascript
如何使用jQUery获取选中radio对应的值(一句代码)
Jun 03 Javascript
js+css实现导航效果实例
Feb 10 Javascript
AngularJS实现元素显示和隐藏的几个案例
Dec 09 Javascript
基于JavaScript实现熔岩灯效果导航菜单
Jan 04 Javascript
微信小程序 跳转传参数与传对象详解及实例代码
Mar 14 Javascript
详解webpack3如何正确引用并使用jQuery库
Aug 26 jQuery
JavaScript EventEmitter 背后的秘密 完整版
Mar 29 Javascript
详解Vue 匿名、具名和作用域插槽的使用方法
Apr 22 Javascript
详解微信小程序轨迹回放实现及遇到的坑
Feb 02 Javascript
javascript iframe内的函数调用实现方法
Jul 19 #Javascript
9个javascript语法高亮插件 推荐
Jul 18 #Javascript
Google Map Api和GOOGLE Search Api整合实现代码
Jul 18 #Javascript
比较简单的异步加载JS文件的代码
Jul 18 #Javascript
用showModalDialog弹出页面后,提交表单总是弹出一个新窗口
Jul 18 #Javascript
DOM 基本方法
Jul 18 #Javascript
javascript 全角转换实现代码
Jul 17 #Javascript
You might like
php 全局变量范围分析
2009/08/07 PHP
纯php打造的tab选项卡效果代码(不用js)
2010/12/29 PHP
理解PHP中的stdClass类
2014/04/18 PHP
Thinkphp模板中截取字符串函数简介
2014/06/17 PHP
PHP正则匹配到2个字符串之间的内容方法
2018/12/24 PHP
Locate a File Using a File Open Dialog Box
2007/06/18 Javascript
extjs form textfield的隐藏方法
2008/12/29 Javascript
jquery struts 验证唯一标识(公用方法)
2013/03/27 Javascript
把jQuery的类、插件封装成seajs的模块的方法
2014/03/12 Javascript
jQuery is()函数用法3例
2014/05/06 Javascript
javascript与有限状态机详解
2014/05/08 Javascript
javascript执行环境及作用域详解
2016/05/05 Javascript
Vue2.0组件间数据传递示例
2017/03/07 Javascript
js实现年月日表单三级联动
2020/04/17 Javascript
Angular 作用域scope的具体使用
2017/12/11 Javascript
React Native使用fetch实现图片上传的示例代码
2018/03/07 Javascript
JavaScript使用递归和循环实现阶乘的实例代码
2018/08/28 Javascript
JavaScript创建对象方法实例小结
2018/09/03 Javascript
Vue.js的复用组件开发流程完整记录
2018/11/29 Javascript
JS对象属性的检测与获取操作实例分析
2020/03/17 Javascript
原生js+canvas实现验证码
2020/11/29 Javascript
[04:39]显微镜下的DOTA2第十三期—Pis卡尔个人秀
2014/04/04 DOTA
[01:58]最残酷竞争 2016国际邀请赛中国区预选赛积分循环赛回顾
2016/06/28 DOTA
python使用urllib2提交http post请求的方法
2015/05/26 Python
Python语言实现百度语音识别API的使用实例
2017/12/13 Python
浅谈numpy数组的几种排序方式
2017/12/15 Python
Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式
2020/01/10 Python
python利用JMeter测试Tornado的多线程
2020/01/12 Python
python 判断一组数据是否符合正态分布
2020/09/23 Python
Python使用grequests并发发送请求的示例
2020/11/05 Python
html5使用window.postMessage进行跨域实现数据交互的一次实战
2021/02/24 HTML / CSS
工商企业管理专业自荐信范文
2014/04/12 职场文书
爱心活动计划书
2014/04/26 职场文书
公司合作意向书范文
2014/07/30 职场文书
社区娱乐活动方案
2014/08/21 职场文书
某药房的新员工入职告知书!
2019/07/15 职场文书