父类:

// 定义一个动物的类
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. kubernetes 1.15 有哪些让人眼前一亮的新特性?

    原文链接:kubernetes 1.15 有哪些让人眼前一亮的新特性? 2019 年 6 月 20 日,Kubernetes 重磅发布了 1.15 版本,不过笔者忙到现在才有空认真来看一下到底更新了哪 ...

  2. CRLF will be replaced by LF in XXX when git commit

    转载自Git-warning: CRLF will be replaced by LF in XXX 今天,普通平凡的一天,平凡的使用 git add .,然后又出现一个之前没遇到的错误提示 . 真开 ...

  3. MOOC 编译原理笔记(一):编译原理概述以及程序设计语言的定义

    编译原理概述 什么是编译程序 编译程序指:把某一种高级语言程序等价地转换成另一张低级语言程序(如汇编语言或机器代码)的程序. 高级语言程序-翻译->机器语言程序-运行->结果. 其中编译程 ...

  4. 基准测试工具:Wrk初识

    最近和同事聊起常用的一些压测工具,谈到了Apache ab.阿里云的PTS.Jmeter.Locust以及wrk各自的一些优缺点和适用的场景类型. 这篇博客,简单介绍下HTTP基准测试工具wrk的基本 ...

  5. K8S学习笔记之Grafana App for Kubernetes的配置

    Grafana有一套针对Kubernetes监控的APP,和Grafana-Zabbix App类似,但是配置咋一看比较麻烦,主要参数都是来自K8S. 这款APP的详细介绍请参考Grafana App ...

  6. Python删除列表元素的3种方法

    之前看教程的时候比较着急,对这些基础掌握不好,过来回顾一下 使用del语句删除 lis = [1, 2, 3, 'a', 'b'] print(lis) del lis[0] print(lis) 输 ...

  7. Calendar类set方法中的坑

    最近写了一个支付宝微信对账报表,发现系统金额比支付宝微信的少好多,左查右查发现是追缴金额没统计到,再一查发现月结束日期为2019-09-31,9月咋会有31,为啥呢就追缴金额不行呢,因为其他类型用TI ...

  8. Ueditor 关于视频上传相关问题

      !!!每次改动后记得,清除一下浏览器缓存再试 !!!   4点: 1.修复编辑时视频不能预览问题: 2.插入视频的时候.在预览的窗口提示 “输入的视频地址有误,请检查后再试!” 3.ueditor ...

  9. HTML5 新增文本标签

    一.mark 标记文本 <mark> 标签定义带有记号的文本,表示页面中需要突出显示或高亮显示的信息. 通常在引用原文的时候使用 mark 元素,目的是引起当前用户的注意. 语法格式: & ...

  10. nano命令

    1. 禁止自动换行 # nano -w xxx 2. 保存 Ctrl+O 3. 退出 Ctrl+X 4. 撤销 在请求确认文件名时按Ctrl+C来取消 5. 剪切 Ctrl+K 移动多行,只需多按几次 ...