Prototype和call(apply)结合实现继承
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function Test(a,b)
{
this.A = a;
this.B = b;
this.say = function(){
alert("Test-C");
}
}
Test.sum = function(a,b)
{
return new Test(this.A + a, this.B + b);
}
Test.prototype.update = function()
{
alert("Test-update");
}
function TestChild1(){
this.say = function(){
alert("TestChild1-C");
}
}
//TestChild1.prototype = new Test(2, 3);
TestChild1.prototype = new Test();
function TestChild2(a, b){
//Test.call(this, a ,b);
this.say = function(){
alert("TestChild2-C");
}
Test.call(this, a ,b);
}
TestChild2.prototype = new Test();
var test1 = new TestChild1();
test1.say();
test1.update();
var test2 = new TestChild2(1, 2);
test2.say();
test2.update();
</script>
</head>
<body>
<div id = "testPrototype">test</div>
</body>
</html>
上面的代码Test是父类,TestChild1和TestChild2是子类,test1和test2分别是TestChild1和TestChild2的实例。
一.带参数的prototype继承方法的问题
//TestChild1.prototype = new Test(2, 3);
TestChild1.prototype = new Test();
如果TestChild1通过上面一句继承Test的话,那么TestChild1的所有实例的A和B都是固定的2和3。
所以继承的时候,带有参数的构造函数一般通过call和apply来继承,比如TestChild2继承的Test的方法。
二.Test.call(this, a ,b)不同位置的意义
function TestChild2(a, b){
Test.call(this, a ,b); ----位置1
this.say = function(){
alert("TestChild2-C");
}
//Test.call(this, a ,b); ----位置2
}
Test.call(this, a ,b);放在位置1和位置2的区别是,位置1的话,先继承父类的say函数,子类里面的say函数会将父类的say函数覆盖,因为javascript是按照顺序执行的。位置2的话,则是先继承父类的say,子类会将父类的重写,一般是放在位置1。
三.二者结合的继承方法
function TestChild2(a, b){
//Test.call(this, a ,b);
this.say = function(){
alert("TestChild2-C");
}
Test.call(this, a ,b);
}
TestChild2.prototype = new Test();
var test2 = new TestChild2(1, 2);
test2.say();
test2.update();
再看TestChild2的继承方法,则是结合了call和prototype两者。
如果去掉TestChild2.prototype = new Test();的话,test2.update();是访问不到的,因为Test.call(this, a ,b);只继承了构造函数。
四.父类函数都写在构造函数里的缺点
父类的函数都写在构造函数里的缺点,比如这样的形式。
function Test(a,b)
{
this.A = a;
this.B = b;
this.say = function(){
alert("Test-C");
}
}
say方法,每次生成一个实例,都必须在内存中生成一次,这样既占用内存效率又低。
最好的方案是,让say方法在内存中只生成一次,所有的实例都指向那个内存地址。要解决这个问题所以要采用prototype,例如下面的形式。
Test.prototype.update = function()
{
alert("Test-update");
}
五. 总结
总结:通过call来调用父类带参构造函数,通过 子类.prototype=new 父类() 来继承父类的方法。如果子类想要覆盖父类的方法,可以用TestChild2.prototype.say = function(){}。
把不变的属性和方法定义在prototype上面。