Javascript面向对象 --3 -- 【继承】

本文详细阐述了JavaScript中类继承的基本概念,并通过实例演示了解决常见问题的方法,包括继承基类的静态方法和属性、优化内存使用以及实现类继承的函数等。文章最后提供了实现类继承的代码示例,并介绍了两种实现继承的方式:使用原型链和拷贝属性。

 最佳实践:

(1) 定义基类,在基类构造函数中定义属性和私有方法,在基类的prototype中连接方法(function)

(2) 定义一个空对象F,空对象的prototype属性指向基类的prototype属性

(3) 定义子类,在子类的构造函数中调用基类的call方法

(4) 设置子类的prototype属性为(2)F的示例(new 一个 F)

具体,建下面 第3部分.

 

1. javascript继承,在子类的构造函数的第一行执行 基类的call方法.

 

//定义一个基类
  function Animal()
  {
    this.species = "动物"; 
  }
  
  //定义一个子类
  function Cat(name,color)
  {
     Animal.call(this);//相当于调用基类的构造函数
     this.name = name;
     this.color = color;
  } 
  
  var aCat = new Cat('Tom','black');
  console.log(aCat);

 上面console.log(aCat);代码的输出为:

 

Cat {species: "动物", name: "Tom", color: "black"}

 

从这个输出可见这里子类正确的获得了基类的species属性.

 

 

这样做有两个问题:

(1)  基类的prototype中的属性和方法将不被继承.

(2)  基类的静态属性和方法不被继承

代码如下:

 

//定义一个基类
  function Animal()
  {
    this.species = "动物"; 
  }
  
  Animal.prototype.show = function() { alert('This is An Animal.');}; //定义基类一个普通方法
  
  Animal.legCount=4; //定义动物有4条腿,类的静态属性
  Animal.TestStaticFunction = function() {alert('TestStaticFunction.');};//基类,静态方法
  
  //定义一个子类
  function Cat(name,color)
  {
     Animal.call(this);//相当于调用基类的构造函数,将基类的属性继承过来,但仅限于在基类的构造函数中定义的属性
     this.name = name;
     this.color = color;
  } 
  
  var anAnimal = new Animal();
  var aCat = new Cat('Tom','black');
  
  console.log(Animal.legCount); //4,基类静态属性,使用类访问,正常
  //console.legCount(anAnimal.legCount);//报错,静态属性只能通过类访问
  Animal.TestStaticFunction(); //基类静态方法,使用类访问,正常
  //anAnimal.TestStaticFunction(); //报错,静态属性只能通过类访问
  
  console.log(aCat); 
  console.log(aCat.legCount);//undefined,静态属性,只能通过类访问(Java中能通过实例访问静态属性)
  console.log(Cat.legCount); //undefined,静态属性,不能继承
  //Cat.TestStaticFunction(); //报错,Cat没有从基类继承 静态方法 TestStaticFunction()
  
  anAnimal.show(); //基类prototype中方法,正常访问
  //aCat.show();   //报错,没有show()方法
 

 

上面的问题(2)解决方法 参见 

http://jackyin5918.iteye.com/blog/1973113

(非构造函数继承_解决Javascript不能继承基类静态方法和静态变量)

 

下面解决问题(1)  基类的prototype中的属性和方法将不被继承

 

2. 解决 基类的prototype中的属性和方法将不被继承

使用下面代码:

 

//定义一个基类
  function Animal()
  {
    this.species = "动物"; 
  }
  
  Animal.prototype.show = function() { alert('This is An Animal. name=' + this.name);}; //定义基类一个普通方法
  
  Animal.legCount=4; //定义动物有4条腿,类的静态属性
  Animal.TestStaticFunction = function() {alert('TestStaticFunction.');};//基类,静态方法
  
  //定义一个子类
  function Cat(name,color)
  {
     Animal.call(this);//相当于调用基类的构造函数,将基类的属性继承过来,但仅限于在基类的构造函数中定义的属性
     this.name = name;
     this.color = color;
  } 
  
  Cat.prototype = new Animal();     //基类的prototype指向 一个新的Animal()对象,
  //通过prototype链(原型链)连接到基类的prototype上,从而实现继承基类的prototype
  Cat.prototype.constructor = Cat; //因为每个类的prototype对象都有个constructor属性,指向类自己,
  //这里需要Cat.prototype其实是Animal,而Animal的constructor是指向Animal的,
  //造成了Cat的constructor指向了Animal,产生混乱,需要修正过来

  var anAnimal = new Animal();
  var aCat = new Cat('Tom','black');
  
  console.log(aCat); 
  anAnimal.show(); //基类prototype中方法,正常访问,(但基类中this.name未定义)
  aCat.show();     //正常,通过prototype方式继承了基类prototype中的方法
 上面代码,解决了基类prototype中方法和属性不能继承问题,但是也产生了一个新问题,

 

就是在定义子类的时候 调用

Cat.prototype = new Animal();     //基类的prototype指向 一个新的Animal()对象,

这一句时,生成了一个基类对象Animal(),造成了内存浪费,应该避免.

 

3. 优化,解决内存浪费问题

使用下面代码,基本上可以完美实现继承:

//定义一个基类
  function Animal()
  {
    this.species = "动物"; 
  }
  
  Animal.prototype.show = function() { alert('This is An Animal. name=' + this.name);}; //定义基类一个普通方法
  
  Animal.legCount=4; //定义动物有4条腿,类的静态属性
  Animal.TestStaticFunction = function() {alert('TestStaticFunction.');};//基类,静态方法
  
  //定义一个子类
  function Cat(name,color)
  {
     Animal.call(this);//相当于调用基类的构造函数,将基类的属性继承过来,但仅限于在基类的构造函数中定义的属性
     this.name = name;
     this.color = color;
  } 
  
  var EmptyObject = function(){}; //
 EmptyObject.prototype = Animal.prototype;
 Cat.prototype = new EmptyObject();  //修改Cat的prototype不会影响到基类的prototype
  Cat.prototype.constructor = Cat;    //因为每个类的prototype对象都有个constructor属性,指向类自己,
  //这里需要Cat.prototype其实是Animal,而Animal的constructor是指向Animal的,
  //造成了Cat的constructor指向了Animal,产生混乱,需要修正过来

  var anAnimal = new Animal();
  var aCat = new Cat('Tom','black');
  
  console.log(aCat); 
  anAnimal.show(); //基类prototype中方法,正常访问,(但基类中this.name未定义)
  aCat.show();     //正常,通过prototype方式继承了基类prototype中的方法

 

4. 实现类继承的函数:

    

function extend(Child, Parent) {

    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;
  }

 5. 另一种实现继承的方式--拷贝属性方式

function extend2(Child, Parent)
 {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
      c[i] = p[i];
      }
    c.uber = p;
  }

 

 

这部分主要学习了下面两篇文章:

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html

还有参考了这个:

http://msdn.microsoft.com/zh-cn/magazine/cc163419.aspx#S4

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值