<script>
// 一个有趣的现象,也是一个值得分析的区别:
Object.extend = function (destination,source){
// 首先,这个循环很奇妙,这个 property 是什么? 数组下标?
for(property in source){
destination[property] = source[property];
}
return destination;
}
// 那么这里的 Object.extend 与 Object.prototype.extend 的区别是什么?
// Object.extend 是属于类本身,而 Object.prototype.extend 所定义的方法属于所有的继承类?
Object.prototype.extend = function (object){
return Object.extend.apply(this,[this,object]);
}
/**//*
这里 extend 函数是为所有派生自 Object 的子类添加 extend 方法
1. 你可以把 extend 理解为 Object 静态方法 ,也就是 Object.extend ,是 Object 本身独有的
2. 是 Object 添加 extend 公用方法,而他本身就是调用 Object.extend() 的,然后使用 apply 使得
调用函数执行范围在 object.prototype 里,而不是 Object 自己,否则以后从 Object 或其派生
类创建出的实例得不到 extend 中传入的参数的,这里 apply 的第一个参数就是 Object.prototype
第二个参数是第一个方法的参数
3. 是 extend 方法的应用
*/
/**//*
来写一个例子来验证说法是否正确:(也就是如果不用 apply ,那么以后从)
*/
// 验证循环的奇妙现象
var arr = new Array("China","England","USA");
for(obj in arr){
alert(obj); // output "0","1","2" ,也就是数组的下标
}
//定义一个抽象基类base,无构造函数 (严格的说,base 类是不能被实例化的,但是我们却可以不规范的实例化,比如 (1) 所示)
function base(){}
/**//*
通过 base.prototype = {} 以及 base.prototype.oninit = function(){} 两种方式我们可以看到,prototype 本身就
是一个对象,而一个对象的赋值方式可以有两种形式,一种,就是用 key : value 的形式,也就是
base.protype = {
key : value
}
而另一种形式就是 直接赋值的形式,也就是 base.protype.key = value
也就是说 obj = {
key : value
}
和 obj.key = value
是等价的
*/
base.prototype={
initialize:function(){
this.oninit(); //调用了一个虚方法
}
}
/**//***** base 类不规范的实例化(解释性的语言就是这样,呵呵) ********/
/**//*
base.prototype.oninit = function (){
alert('方法 oninit() 被调用');
}
*/
// var ba = new base(); // base 被实例化了(关键点是,只要在调用的时候,oninit()方法被定义出来了就行!)
// 让一个 class 继承于 base 并实现其中的 oninit 方法
function class1(){}
class1.prototype = (new base()).extend(
{
oninit : function (){ // 实现抽象基类的 oninit 虚方法
// oninit 函数实现
}
}
);
var cs = new class1();
alert(cs instanceof base); // 竟然能够 ouput "true"
/**//* */
/**//* 这样,当在 class1 实例中调用继承得到 initialize 方法时,就会自动执行派生类中的 oninit() 方法。
从这里也可以看到解释型语言执行的特点,它们只有运行到某一个方法调用时,才会检查该方法是否存在,
而不会像编译型语言一样,在编译阶段就检查方法是否存在, JavaScript 中则避免了这个问题,当然,如
过希望在虚类中添加虚方法的一个定义,也是可以的。只要在派生类中覆盖此方法即可.
例如,定义一个抽象基类 base1,无构造函数
*/
function base1(){}
base1.prototype = {
initilize:function(){
this.oninit(); // 这里调用了一个虚方法
},
oninit : function(){} // 虚方法是一个空方法,由派生类产生
}
/**//**********************************************************************************/
/**//* 使用抽象类的示例: */
/**//*
仍然以 prototype-1.3.1 为例,其中定义了一个类的创建模型:
*/
// Class1 是一个全局对象,有一个方法 create ,用于返回一个类,
var Class1 = {
create : function (){
return function (){
this.initialize.apply(this,arguments);
}
}
}
/**//*
这里 Class1 是一个全局对象,具有一个方法 create,用于返回一个函数(类),可以用如下
语法:
*/
var c1 = Class1.create();
/**//*
这样定义类的方式就和定义函数的方式区分开来,使 JavaScript 语言更具备面向对象的特点。现在
来看这个返回的函数(类):
function (){
this.initilize.apply(this,arguments);
}
这个函数也是一个类的构造函数,当 new 这个类的时候便会执行,他调用了一个 initilize() 的方法,
从名字看来,是类的构造函数。从类的角度来看,它是一个虚方法,是未定义的。但这个虚方法的实现
并不是在派生类中实现的,而是创建完一个类后,在 prototype 中定义的,例如 prototype 可以这样
写:
var c1 = Class.create();
c1.protype = {
initilize : function( userName ){
alert('hello,' + userName);
}
}
这样,每次创建类的实例的时候,initialize 方法都会得到执行。从而实现了将类的构造函数和类成员一起
定义的功能。其中,为了能够给构造函数传递参数,使用了这样的语句。
function (){
this.initilize.apply(this,arguments);
}
实际上,这里的 arguments 是 function() 中所传进来的参数,也就是 new class1(args) 中传递进来的参数,
现在要把 args 传递给 initilize ,巧妙的使用了 apply() ,注意不能写成:
this.initilize(arguments);
这是将 arguments 数组作为一个参数传递给 initilize() 方法,而 apply() 方法则可以将 arguments() 对象
的元素作为一组参数传递过去,这是一个很巧妙的实现。
尽管这个例子在 prototype-1.3.1 中不是一个抽象类的概念,而是类的一种设计模式。但实际上,可以把
Class.create() 返回的类看做所有类的共同基类,它在构造函数中调用了一个虚方法 initilize ,所有继承
于它的类都必须实现这个方法,完成构造函数的功能。它们得以实现的本质就是对 prototype 的操作.
*/
</script>
posted on 2008-12-07 18:23
CopyHoo 阅读(1548)
评论(0) 编辑 收藏 所属分类:
JavaScript