发表于: 2017-05-03 21:58:51

1 1055


1.背景介绍

JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一。那么如何在JS中实现继承呢?让我们拭目以待。


2.知识剖析

继承概念:


指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力, 继承是类与类或者接口与接口之间最常见的关系.


继承方式:


在基于类的面向对象方式中,对象(object)依靠类(class)来产生。


而在基于原型的面向对象方式中,对象(object)则是依靠构造器(constructor)利用原型(prototype)构造出来的。


JavaScript语言正是如此,它是通过一种叫做原型(prototype)的方式来实现面向对象编程。


继承分类及使用场景:


单继承(实例类继承) 场景:扩充/改善基类


多继承(纯抽象类继承) 场景:实现多态


3.常见问题

js如何实现继承?


4.解决方案

既然要实现继承,那么首先我们得有一个父类,代码如下:

// 定义一个动物类

function Animal (name) {

  // 属性

  this.name =  'Animal';

  // 实例方法

  this.sleep = function(){

    console.log(this.name + '正在睡觉!');

  }

}

// 原型方法

Animal.prototype.eat = function(food) {

  console.log(this.name + '正在吃:' + food);

};


方法一:原型链继承


核心: 将父类的实例作为子类的原型

function Cat(){

}

Cat.prototype = new Animal();

Cat.prototype.name = 'cat';


// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.eat('fish'));

console.log(cat.sleep());

console.log(cat instanceof Animal); //true

console.log(cat instanceof Cat); //true


特点:


非常纯粹的继承关系,实例是子类的实例,也是父类的实例


父类新增原型方法/原型属性,子类都能访问到


缺点:


要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中


无法实现多继承


来自原型对象的引用属性是所有实例共享的,在编码实战中详细讲解.


创建子类实例时,无法向父类构造函数传参


方法二:构造继承


核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)


function Cat(name){

  Animal.call(this);

  this.name = name;

}


// Test Code

var cat = new Cat("Tom");

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // false

console.log(cat instanceof Cat); // true


特点:


解决了1中,子类实例共享父类引用属性的问题 创建子类实例时,实例可以向父类传递参数 可以实现多继承(call多个父类对象)


缺点:


实例并不是父类的实例,只是子类的实例。


只能继承父类的实例属性和方法,不能继承原型属性/方法。


无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。


方法三:组合继承


核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

function Cat(name){

  Animal.call(this);

  this.name = 'Tom';

}

Cat.prototype = new Animal();


// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); // true

特点:


弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法 既是子类的实例,也是父类的实例 不存在引用属性共享问题 可传参 函数可复用


缺点:


调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)


5.编码实战

关键点:属性查找过程


执行tom.features.push,首先找tom对象的实例属性(找不到), 那么去原型对象中找,也就是Animal的实例。发现有,那么就直接在这个对象的 features属性中插入值。 在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么去原型上找。 刚好原型上有,就直接返回,但是注意,这个原型对象中features属性值已经变化了。


6.扩展思考

继承、依赖、接口的区别?


7.参考文献

参考:JS继承的实现方式


参考:总结继承的几种方式


参考:UML类图详解接口、继承、依赖


返回列表 返回列表
评论

    分享到