JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一。

既然要实现继承,那么我们先定义一个父类:

// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
alert(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
alert(this.name + '正在吃:' + food);
};

1、原型链继承

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

function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat'; // Test Code
var cat = new Cat();
alert(cat.name);
alert(cat.eat('fish'));
alert(cat.sleep());
alert(cat instanceof Animal); //true
alert(cat instanceof Cat); //true

特点:

  1. 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  2. 父类新增原型方法/原型属性,子类都能访问到

缺点:

  1. 要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
  2. 无法实现多继承
  3. 来自原型对象的引用属性是所有实例共享的
  4. 创建子类实例时,无法向父类构造函数传参

2、借用构造函数继承

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

function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
} // Test Code
var cat = new Cat();
alert(cat.name);
alert(cat.sleep());
alert(cat instanceof Animal); // false
alert(cat instanceof Cat); // true

特点:

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

缺点:

  1. 实例并不是父类的实例,只是子类的实例
  2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
  3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3、组合继承

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

function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal(); // Test Code
var cat = new Cat();
alert(cat.name);
alert(cat.sleep());
alert(cat instanceof Animal); // true
alert(cat instanceof Cat); // true

特点:

  1. 弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
  2. 既是子类的实例,也是父类的实例
  3. 不存在引用属性共享问题
  4. 可传参
  5. 函数可复用
  6. 可以实现多继承(同上)

缺点:

  1. 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)(仅仅多消耗了一点内存)

4原型式继承

核心:继承已有的对象而不是函数

//对传入的对象执行一次浅复制
function object(o){
function F(){}
F.prototype = o;
return new F();
}
//例子
var Animal = {
name:"cat",
friend:["aaron","cassic"]
}
var cat=object(Animal);
cat.name="sss";
cat.friend.push("aseaff");
alert(cat.name);
alert(cat.friend);

特点:

  1. 没有必要创建构造函数,只是想让一个对象与另一个对象保持类似

缺点:

  1. 与原型模式一样,包含引用类型的属性值会共享

5寄生式继承

核心 与原型式继承紧密相关,只是多了方法

//对传入的对象执行一次浅复制
function object(o){
function F(){}
F.prototype = o;
return new F();
}
//增强对象
function createobject(o){
var clone=object(o);
clone.sayname=function(){
alert("hi");
};
return clone;
}
//例子
var Animal = {
name:"cat",
friend:["aaron","cassic"]
}
var cat=createobject(Animal);
cat.sayname();

特点:

  1. 没有必要创建构造函数,只是想让一个对象与另一个对象保持类似
  2. 与原型式继承相比,有了自己的方法

缺点:

  1. 与原型式继承一样,包含引用类型的属性值会共享

6、寄生组合继承

核心:通过寄生方式,创建空函数,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
function aaron(o,y){
var Super = function(){};
Super.prototype=y.prototype;
o.prototype=new Super();
o.prototype.constructor=o;
}
aaron(Cat,Animal);
// Test Code
var cat = new Cat();
alert(cat.name);
cat.sleep();
alert(cat instanceof Animal); // true
alert(cat instanceof Cat); //true

特点:

  1. 堪称完美

缺点:

  1. 实现较为复杂
  2. 不能实现多继承(不完美,同上)

下面介绍多继承

7 拷贝继承

function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
} // Test Code
var cat = new Cat();
alert(cat.name);
cat.sleep();
alert(cat instanceof Animal); // false
alert(cat instanceof Cat); // true

特点:

支持多继承

缺点:

效率较低,内存占用高(因为要拷贝父类的属性)(使用 for in 能遍历原型方法)

8 组合使用构造函数和拷贝实现多继承

function Parent1(name,age){
this.name = name;
this.age = age;
this.height=180;
}
Parent1.prototype.say = function(){
alert('hi');
}
function Parent2(name,age,weight){
this.name = name;
this.age = age;
this.weight = weight;
this.height = 170;
this.skin='yellow';
}
Parent2.prototype.walk = function(){
alert('walk');
} function Child(name,age,weight){
Parent1.call(this,name,age);
Parent2.call(this,name,age,weight);
} for(var i in Parent1.prototype){Child.prototype[i] = Parent1.prototype[i]}
for(var i in Parent2.prototype){Child.prototype[i] = Parent2.prototype[i]} var c1 = new Child('xiaoming',10,8);
console.log(c1); //Child { name="xiaoming", age=10, height=170, 更多...}
console.log(c1.constructor);//Child(name,age,weight)

特点:javascript的多继承其实就是前面介绍的js循环拷贝继承的多次使用

总结:javascript是可以利用call方法和prototype属性来实现多继承的。继承方法与单继承相似,只是将需要继承的多个父类依次实现,另外对于属性或共有方法重命的时候,以最后继承的属性和方法为主。因为会覆盖前面的继承。

最好的两个继承是寄生组合继承和循环拷贝继承,但是寄生组合继承不能完美实现多继承,会漏掉父类原型方法,只有循环拷贝继承可以完美实现多继承。

JS继承的几种方式的更多相关文章

  1. js 继承的几种方式

    JS继承的实现方式: 既然要实现继承,那么首先我们得有一个父类,代码如下: function Animal(name) { // 属性 this.name = name || '小白'; // 实例方 ...

  2. 20. js继承的6种方式

    想要继承,就必须要提供个父类(继承谁,提供继承的属性) 一.原型链继承 重点:让新实例的原型等于父类的实例. 特点: 1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性.( ...

  3. 理解js继承的6种方式

    想要继承,就必须要提供个父类(继承谁,提供继承的属性) 一.原型链继承 重点:让新实例的原型等于父类的实例. 特点:1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性.(新 ...

  4. js继承的6种方式

    想要继承,就必须要提供个父类(继承谁,提供继承的属性) 一.原型链继承 重点:让新实例的原型等于父类的实例. 特点:1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性.(新 ...

  5. js实现继承的5种方式 (笔记)

    js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...

  6. javascript(js)创建对象的模式与继承的几种方式

    1.js创建对象的几种方式 工厂模式 为什么会产生工厂模式,原因是使用同一个接口创建很多对象,会产生大量的重复代码,为了解决这个问题,产生了工厂模式. function createPerson(na ...

  7. js 实现继承的几种方式

    //js中实现继承的几种方式 //实现继承首先要有一个父类,先创造一个动物的父类 function Animal(name){ this.name = name; this.shoot = funct ...

  8. js 实现继承的6种方式(逐渐优化)

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  9. JS继承的原理、方式和应用

    概要: 一.继承的原理 二.继承的几种方式 三.继承的应用场景 什么是继承? 继承:子类可以使用父类的所有功能,并且对这些功能进行扩展.继承的过程,就是从一般到特殊的过程.要了解JS继承必须首先要了解 ...

随机推荐

  1. <六> jQuery 获得内容和属性

    获得内容 三个简单实用的用于 DOM 操作的 jQuery 方法: text() - 设置或返回所选元素的文本内容 html() - 设置或返回所选元素的内容(包括 HTML 标记) val() - ...

  2. 简单3d RPG游戏 之 001 生命条(一)

    1.创建一个新项目,引用如下的包: 2.将asset里的First Person Controller拖入project作为游戏角色,将其命名为Player,将mainCamera删除,这样就是用Pl ...

  3. python 图片上添加数字源代码

    最近因工作需要,需要在图片上添加数字,查询了资料,自己写了一个方法,并进行了测试,由于代码用到了PIL库,需要下载安装,下载地址:http://www.pythonware.com/products/ ...

  4. vs2015 好用插件

    备用一下,方便自己查阅 Viasfora 高亮,让自己看代码舒服 ClaudiaIDE 更换编辑器背景 Markdown Mode 编辑Markdown Glyphfriend 图像文字支持 Web ...

  5. UVALive 6602 Counting Lattice Squares

    给定一个n*m的网格,求面积为奇数的正方形有多少个. 首先是n*m个面积为1的,然后剩下的要么是边长为奇数,要么被这样一个奇数边长所包围. 原因如下: 对于一个边长不平行于坐标抽的正方形,其边长一定是 ...

  6. 李洪强实现横向滚动的View<二>

    上一节中我们已经实现了一个带有图片,标题和价格label 的UIView 这节我们用这个view实现一个横向滚动的UIcollectionView 实现的效果如下:  01 - 创建CFTyreScr ...

  7. Earth Mover's Distance (EMD)

    原文: http://d.hatena.ne.jp/aidiary/20120804/1344058475作者: sylvan5翻译: Myautsai和他的朋友们(Google Translate. ...

  8. 程序模拟浏览器请求及会话保持-python实现

    http://www.cnblogs.com/zxlovenet/p/4006649.html

  9. MySQL的SQL_CALC_FOUND_ROWS

    分页程序一般由两条SQL组成: SELECT COUNT(*) FROM ... WHERE .... SELECT ... FROM ... WHERE LIMIT ... 如果使用SQL_CALC ...

  10. 【HDOJ】3652 B-number

    终于自己写出来一道数位DP啊.继续训练DP. /* 3652 */ #include <iostream> #include <sstream> #include <st ...