JS OO
2011-03-11
作者:stroll
来自:无忧脚本 作者已授权
原帖地址:http://be10.ods.org/51js/viewthread.php?tid=9958
这篇文章是研究关于 JS OO 的继承机制,但绝对不是以前的那种哦,而是探讨新的方式。。如果你对OO感兴趣,就让我们继续吧!
也许你一直对 Script5.5 里面的 call apply 等方法很有想法?他到底是怎么工作的?我也一直很好奇,就是没时间研究。 今天就花些时间一起研究一下?呵呵~~~
记得以前我也介绍过关于 JS OO 的实现方式
这是父类 A 的代码 function A(){ this.doA = function(){ alert("doA"); } }
对于 call apply 的方式 IE5.5 以上 function B(){ A.call(this); }
对于 prototype 方式 IE 5.0 function B(){
}
B.prototype = new A();
只要使用以上方式,B 类 的 对象 就可以使用 A 类的方法了。。由于 call apply 现在对我们来说是未知数,我们就暂时不管他,先从 prototype 这个SB开刀。。
prototype 是什么意思呢? Script 手册上说是返回 【返回对象类型原型的引用】。晕~~什么叫原型啊?我也不懂~呵呵
不过结合他所说的 【用 prototype 属性提供对象的类的一组基本功能。对象的新实例“继承”赋予该对象原型的操作。】 我们就可以明白
类名.prototype.方法名 = xxxx 和 在类内部定义 this.方法名 = xxxx 是完全等价的
明白了这些,就让我们继续了解 类名.prototype = new 父类名() 的工作原理吧? 不过就此打住,我不想再对这个实现方式说什么了。为什么?因为我觉得他并不是有效且明确的继承方式。。嘿嘿,我发现更好更容易明白的方式来继承。
在此之前先让我们来了解一些 函数机制
function C(){
this.do1 = function(){
this.do2 = function(){
alert("do2");
}
}
}
var o = new C();
o.do1();
o.do2(); // 结果是 do2
可见【类的 属性/方法 是可以在运行期间添加的】(一观众上台,二话不说抡起砖块就砸:“拷,这谁不知道啊,用你说!浪费老子大半天时间!!”) 别瞧不起这个简单的原理,他可是有效实现类继承的前提。。。(当!“那还不快说,这么多废话!” 小逛摸了摸头上的包继续开说~~)
让我们看看下面这段代码: function P(){ this.do2 = function(){ alert("do2"); } }
function C(){
P();
}
var o = new C();
o.do2(); // 结果 是 do2
看出些什么了吧?嗯嗯,台下不少聪明的听众已经开始自行实现 call apply 了。。 如果是稍微比我聪明点,但却还不能理解call apply工作原理的请往下看。。
首先再跟大家介绍一位靓妹: constructor,她能够返回 创建该对象的函数。比如: function C1(value){ this.data = value this.create = function(value){ return new this.constructor(value); // 等价 return new C1(value) } this.say = function(){ alert("C1 say " + this.data); } } var o = new C1("你好"); var o2 = o.create("你叫我啊?"); o2.say(); // 结果为 C1 say 你叫我啊?
还有一位帅哥。。 arguments 他是返回函数的参数集合, arguments.length 返回参数个数
arguments[i] 可以获取指定下标的参数
function F(){
alert(arguments.length);
if(arguments.length > 0)
alert("arg[0] = " + arguments[0]);
}
F(1,2,3);
// 结果是
3
arg[0] = 1
说到这里大家应该能领略 constructor 的漂亮 和 arguments 的帅气了吧? 接着我们让 prototype+constructor+arguments联手构造我们的 call 吧。。
Function.prototype.call = function(sonFun){
if(sonFun instanceof Object == false){ // 如果 sonFun 不是 函数
alert("call 方法第一个参数需要有效函数!");
return;
}
sonFun.constructor.prototype.___base = this; // 定义 sonFun 的属性 __base 为当前调用 call 的函数
if(arguments.length == 1){ // 只有一个参数
sonFun.___base();
}else{
var aoEval = new Array();
for(var i=1; i<arguments.length; i++){
aoEval[aoEval.length] = "arguments["+i+"]"
}
aoEval = "sonFun.___base(" + aoEval.join(",") + ")"; // sonFun.__base(arguments[0], ...,arguments[i])
//alert(aoEval)
eval(aoEval);
}
}
function C1(value){
this.data = value
this.say = function(){
alert("C1 say " + this.data);
}
}
function C2(value){
C1.call(this, value);
}
var o = new C2("我是 call 制造的说~~");
o.say()
代码:// 动物类 animal
function animal(bSex){
this.sex = bSex
this.getSex = function(){
return this.sex
}
}
// 类静态变量 (如果你不修改它的话~~)
animal.SEX_G = new Object(); // 雌性
animal.SEX_B = new Object(); // 雄性
// 动物子类 鸟
function bird(bSex){
animal.call(this, bSex);
this.fly = function(iSpeed){
alert("飞行时速高达 " + iSpeed);
}
}
// 动物子类 鱼
function fish(bSex){
animal.call(this, bSex);
this.swim = function(iSpeed){
alert("游动时速高达 " + iSpeed)
}
}
// 鱼 鸟 杂交品种。。。
function crossBF(bSex){
bird.call(this, bSex);
fish.call(this, bSex);
}
var oPet = new crossBF(animal.SEX_G); // 雌性 鱼鸟
alert(oPet.getSex() == animal.SEX_G ? "雌性" : "雄性");
oPet.fly(124)
oPet.swim(254)