父类:

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

1、原型链继承

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

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

特点:

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

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

3.简单,易于实现

缺点:

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

2.无法实现多继承;

3.来自原型对旬的引用属性是所有实例共享的(附录示例1);

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

2、构造继承

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

function Dog(name) {
Animal.call(this);
this.name = name || 'Tom';
} var dog = new Dog();
console.log(dog.name);
console.log(dog.sleep());
console.log(dog instanceof Animal); // false
console.log(dog instanceof Dog); true

特点:

1.解决了1中,子类实例共享父类引用属性的问题

2.创建子类实例时,可以向父类传递参数

3.可以实现多继承(call多个父类对象)

缺点:

1.实例并不是父类的实例,只是子类的实例

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

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

3、实例继承

核心:为父类实例添加新特性,作为子类实例返回

function Cat (name) {
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
} // 测试代码
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

特点:

1.不限制调用方式,不管是new子类() 还是子类(),返回的对象具有相同的效果

缺点:

1.实例是父类的实例,不是子类的实例

2.不支持多继承

4、拷贝继承

function Cat (name) {
var animal = new Animal();
for (var p in animal) {
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
} // 测试代码
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特点:

1.支持多继承

缺点:

1.效率较低,内存占用高(因为要拷贝父类的属性)

2.无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

PS:推荐指数:★(缺点1)

5、组合继承

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

function Cat (name) {
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal(); // 测试代码
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

特点:

1.弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法

2.既是子类的实例,也是父类的实例

3.不存在引用属性共享的问题

4.可传参

5.函数可复用

缺点:

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

推荐指数:★★★★(仅仅多消耗了一点内存)

6、寄生组合继承

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

function Cat (name) {
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
// 将实例作为子类的原型
Cat.prototype = new Super();
})() // 测试代码
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

特点:

1.堪称完美

缺点:

1.实现较为复杂

推荐指数:★★★★(实现复杂,扣掉一颗星)

附录代码:

示例一:

function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉');
}
// 实例引用属性
this.featrues = [];
} function Cat (name) {
}
Cat.prototype = new Animal(); var tom = new Cat('Tom');
var kissy = new Cat('Kissy'); console.log(tom.name); // "Animal"
console.log(kissy.name); // "Animal"
console.log(tom.features); // []
console.log(kissy.features); // [] tom.name = 'Tom-New Name';
tom.features.push('eat'); //针对父类实例值类型成员的更改,不影响
console.log(tom.name); // 'Tom-New Name'
console.log(kissy.name); // 'Animal'
//针对父类实例引用类型成员的更改,会通过影响其他子类实例
console.log(tom.features); // ['eat']
console.log(kissy.features); // ['eat']

原因分析:

关键点:属性查找过程

执行tom.features.push,首先找tom对象的实例属性(找不到),

那么就去原形对象中找,也就是Animal的实例。发现有,那么就直接在这个对象 的features属性中插入值。

在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么就去原型上找。刚好原型上有,就直接返回,但是注意,这个原型对象中features属性值已经变化了。

转载:http://www.cnblogs.com/humin/p/4556820.html

JS实现继承的几种方法的更多相关文章

  1. JS 原型继承的几种方法

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

  2. JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)

    JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...

  3. js对象之间的"继承"的五种方法

    今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...

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

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

  5. ajax请求参数中含有特殊字符"#"的问题 (另附上js编码解码的几种方法)

    使用ajax向后台提交的时候 由于参数中含有#  默认会被截断 只保留#之前的字符  json格式的字符串则不会被请求到后台的action 可以使用encodeURIComponent在前台进行编码, ...

  6. 实现JS继承的几种方法

    总的来说,JS的继承大体上分为两种:借用构造函数方式和原型方式 首先,我们来看看借用构造函数方式的几种做法: //方式一function Person(name, sex){ this.name = ...

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

    这是面试时面试官会经常问到问题: js的继承方式大致可分为两种:对象冒充和原型方式: 一.先说对象冒充,又可分为3种:临时属性方式.call().apply(): 1.临时属性方式: 当构造对象son ...

  8. js(javascript) 继承的5种实现方式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt240 js继承有5种实现方式:1.继承第一种方式:对象冒充  functio ...

  9. JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式

      前  言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...

随机推荐

  1. Java多线程编程(2)--多线程编程中的挑战

    一.串行.并发和并行   为了更清楚地解释这三个概念,我们来举一个例子.假设我们有A.B.C三项工作要做,那么我们有以下三种方式来完成这些工作:   第一种方式,先开始做工作A,完成之后再开始做工作B ...

  2. python3 根据时间获取本月一号和月末日期

    一.概述 有一个统计报表需求,需要知道上个月的第一天和最后一天,来进行上个月的数据统计. 二.代码实现 #!/usr/bin/env python3 # coding: utf-8 import ca ...

  3. 【华为云实战开发】10.经典的C++项目怎么在云端开发?【华为云技术分享】

    1 概述 1.1 文章目的 本文主要想为研发C++项目的企业或个人提供上云指导,通过本文中的示例项目 “音频解析器”,为开发者提供包括项目管理,代码托管,代码检查,编译构建,测试管理的操作指导,覆盖软 ...

  4. SocketChannel简述

    前言 在前面的Channel概述的分类中提到过SocketChannel主要是用来基于TCP通信的通道.这篇文章详细介绍下SocketChannel SocketChannel是什么 SocketCh ...

  5. router单页面多个标签tags的用法<router-view></router-view>

    <keep-alive><router-view :key="path" /></keep-alive>

  6. .net Dapper 实践系列(5) ---事务编辑(Layui+Ajax+Dapper+MySQL)

    目录 写在前面 实践步骤 写在前面 上一小节,我们总结了根据Id查询多表数据,最后返回Json对象给前台的例子.接下来,在这一小节我们要实现多表编辑的操作. 实践步骤 因为上一小节以及创建了Edit视 ...

  7. python3.6安装pyinstaller报错:AttributeError: module 'enum' has no attribute 'IntFlag'

    转载至:https://blog.csdn.net/qq_41185868/article/details/80599336 感谢原作者的分享 解决思路:这可能是由包Enum34引起的.因为Pytho ...

  8. React学习笔记②

    import React,{Component} from 'react'; import Child from './Child.js' class App extends Component{ c ...

  9. 排序算法的c++实现——插入排序

    插入排序的思想是:给定一个待排序的数组,我们从中选择第一个元素作为有序的基态(单个元素肯定是有序的), 然后从剩余的元素中选择一个插入到有序的基态中,使插入之后的序列也是有序状态,重复此过程,直到全部 ...

  10. WIN10分盘

    https://jingyan.baidu.com/article/73c3ce28325dcde50243d94d.html