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. CATransition的动画效果类型及实现方法--老代码备用参考

    实现iphone漂亮的动画效果主要有两种方法,一种是UIView层面的,一种是使用CATransition进行更低层次的控制, 第一种是UIView,UIView方式可能在低层也是使用CATransi ...

  2. Git Commit Template 提交模板

    多人协作开发一个项目时,版本控制工具是少不了的,git是linux 内核开发时引入的一个优秀代码管理工具,利用它能很好使团队协作完成一个项目.为了规范团队的代码提交,也方便出版本时的release n ...

  3. 《深入理解计算机系统》C程序中常见的内存操作有关的典型编程错误

    对C/C++程序员来说,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构成的模块跑起来后才出现内存崩溃,是很让人痛苦的.因为崩溃的位置在时间和空间上,通常是在距真正的错误源一段距离之后才 ...

  4. poj 1631 Bridging signals (二分||DP||最长递增子序列)

    Bridging signals Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9234   Accepted: 5037 ...

  5. 使用jackson对Java对象与JSON字符串相互转换的一些总结

    本文为菠萝大象原创,如要转载请注明出处.http://www.blogjava.net/bolo 代码无真相,为了最简单的说明,我直接上代码. public class User { private  ...

  6. 上传项目到Github

    1.使用根工具(均是图形化的界面) TortoiseGit-1.8.12.0-32bit GitExtensions-2.48.05-SetupComplete 2.大致步骤 首先,你需要一个Gith ...

  7. 10个基于 Ruby on Rails 构建的顶级站点

    本文系国内 ITOM 行业领军企业 OneAPM 工程师翻译整理自 Raviraj Hegde 的文章 Top Sites Built with Ruby on Rails. 就其本身而言,Ruby ...

  8. POJ 3349 Snowflake Snow Snowflakes(哈希)

    http://poj.org/problem?id=3349 题意 :分别给你n片雪花的六个角的长度,让你比较一下这n个雪花有没有相同的. 思路:一开始以为把每一个雪花的六个角的长度sort一下,然后 ...

  9. 李洪强漫谈iOS开发[C语言-016]-变量的作用域

  10. phpexcelreader超级简单使用

    phpexcelreader超级简单使用 该php类可以到官网下载:http://www.codeplex.com/PHPExcel,下载的文件不能直接使用要看下面的备注. 备注: 1.要将olere ...