js继承之call,apply和prototype随谈

时间:2023-03-09 19:20:12
js继承之call,apply和prototype随谈

在js中,call,apply和prototype都可以实现对象的继承,下面我们看一个例子:

  function FatherObj1() {
this.sayhello = "I am join";
this.show = function () {
alert("I am FatherObj1");
};
this.getall = function () { if (arguments)
alert("GetAll:" + arguments[0]);
} }
function FatherObj2() {
this.sayhi = "I am Tom";
this.show = function () {
alert("I am FatherObj2");
}; }
function SonObj() {
this.sayby = "ByeBye";
this.show = function () {
alert("I am SonObj");
}; }

1.call&apply继承

我们先说一下 call和apply 的继承方式,

对于call和apply 在实现继承方面只是传参方式有区别,其他基本相同。

SonObj来继承FatherObj1:

function SonObj() {
this.sayby = "ByeBye";
this.show = function () {
alert("I am SonObj");
};
FatherObj1.call(this); //继承方式1
// FatherObj1.apply(this);//继承方式2 }

这里的 FatherObj1.call(this); 可以理解为把FatherObj1这个对象里的属性和方法委托给this也就是Sonobj,或者遗传给Sonobj,这种方式与C#,Java的继承不同的是:js可以继承多个父类,而C#,java只能继承一个,

那么问题来了,js继承多个父类,而多个父类如果有同名方法或者同名属性,会发生什么事情?

  function SonObj() {
this.sayby = "ByeBye";
this.show = function () {
alert("I am SonObj");
};
FatherObj1.call(this); //继承方式1
FatherObj2.call(this); }

上面代码我让SonObj同时继承FatherObj1和FatherObj2,大家可以看到,在子类和父类对象里都存在同名方法show,

 var son = new SonObj();
son.show();

运行之后的结果是:I am FatherObj2,这个结果说明 FatherObj2的show方法把SonObj的同名方法给重写了,下面我调整一下SonObj里面的方法顺序,

 function SonObj() {
this.sayby = "ByeBye"; FatherObj1.call(this); //继承方式1
FatherObj2.call(this);
this.show = function () {
alert("I am SonObj");
}; }

输出结果:I am SonObj,可见js对同名方法的处理是,执行过程中,后者替代前者,不受子父类的约束,

如果我只想继承FatherObj1的getall方法,不想继承整个类怎么做呢?我们可以这样:

  function SonObj() {
this.sayby = "ByeBye"; this.show = function () {
alert("I am SonObj");
};
}
var son = new SonObj();
var fa = new FatherObj1();
fa.getall.call(son, 1, 2);
fa.getall.apply(son, [1, 2]);

从call和apply 的调用上看,细心的同学应该发现了其中的不同,call的参数是 call(obj,arg1,arg2),而apply的参数是一个对象加一个数组,apply(obj,[arg1,arg2])

我现在给FatherObj2加一个原型方法:

  FatherObj2.prototype.StaticForYou = function () {
alert("FatherObj2_StaticForYou"); };

现在我用SonObj去继承这个方法的话,可以这样写:

 FatherObj2.prototype.StaticForYou.call(SonObj.prototype);

或者:

 FatherObj2.prototype.StaticForYou.call(SonObj);

同样,用apply也可以实现,只是很相同,就不写了。

2 Prototype的继承:

  SonObj.prototype = new FatherObj1();
var son = new SonObj();

这样,son就有了fatherobj1的所有方法,

同样,我们用son来调用show方法

  son.show();

输出结果是:I am SonObj,而不是父类的方法返回结果,是的,prototype的继承其实就是复制父类的方法和属性,如果自己有同名方法或属性,就不去复制,而保留本身的属性或方法。

那如果我想要调用父类的同名方法怎么做呢?可以把上面代码改成

        var father = new FatherObj1();
father.show.call(son);

这样相当于又回到了call和apply的继承问题。

现在我们想,既然用call和apply 可以继承多个父类,那我们同理用prototype来试试:

 SonObj.prototype = new FatherObj1();
SonObj.prototype = new FatherObj2();

这样sonobj会不会继承这两个父类的属性和方法呢?

结果我们发现,已经调用不到FatherObj1的方法了,只能调用到FatherObj2的方法和属性。下面的父类把上面的父类替换掉了。

 SonObj.prototype.StaticForYou = function () {
alert("Static_Come");
}
son.StaticForYou();

输出结果:Static_Come,如果想输出父类的原型方法呢?推一下就出来啦

 FatherObj2.prototype.StaticForYou.call(SonObj);