JS实现继承的几种方法
父类:
// 定义一个动物的类
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实现继承的几种方法的更多相关文章
- JS 原型继承的几种方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...
- js对象之间的"继承"的五种方法
今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...
- js实现继承的5种方式 (笔记)
js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...
- ajax请求参数中含有特殊字符"#"的问题 (另附上js编码解码的几种方法)
使用ajax向后台提交的时候 由于参数中含有# 默认会被截断 只保留#之前的字符 json格式的字符串则不会被请求到后台的action 可以使用encodeURIComponent在前台进行编码, ...
- 实现JS继承的几种方法
总的来说,JS的继承大体上分为两种:借用构造函数方式和原型方式 首先,我们来看看借用构造函数方式的几种做法: //方式一function Person(name, sex){ this.name = ...
- js实现继承的两种方式
这是面试时面试官会经常问到问题: js的继承方式大致可分为两种:对象冒充和原型方式: 一.先说对象冒充,又可分为3种:临时属性方式.call().apply(): 1.临时属性方式: 当构造对象son ...
- js(javascript) 继承的5种实现方式
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt240 js继承有5种实现方式:1.继承第一种方式:对象冒充 functio ...
- JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式
前 言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...
随机推荐
- beego:限制接口访问频率
package utils import ( "github.com/astaxie/beego" "github.com/astaxie/beego/context&q ...
- Django阅读目录
(一)Django框架简介 (二)Django框架之第二篇--app注册.静态文件配置.form表单提交.pycharm连接数据库.django使用mysql数据库.表字段的增删改查.表数据的增删改查 ...
- memcached源码分析一-slab
Slab作为一种内存管理方案,其作用主要有以下2点: a) 避免频繁的内存分配释放造成的内存碎片 b) 减少内存分配操作产生的性能开销 Linux内核数据结构中也有slab的设计,Linux提供了一套 ...
- Elasticsearch常见用法-分布式集群
集群内部工作方式 Elasticsearch用于构建高可用和可扩展的系统.扩展的方式可以是购买更好的服务器(纵向扩展(vertical scale or scaling up))或者购买更多的服务器( ...
- Linux学习笔记之vim操作指令大全
0x00 关于Vim Vim是款强大的文本编辑器,但是众多指令需要学习,这次记录了指令大全方便以后翻阅. Vim的几种模式 正常模式:可以使用快捷键命令,或按:输入命令行. 插入模式:可以输入文本,在 ...
- C#读写修改设置调整UVC摄像头画面-缩放
有时,我们需要在C#代码中对摄像头的缩放进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ...
- 模型文件(checkpoint)对模型参数的储存与恢复
1. 模型参数的保存: import tensorflow as tfw=tf.Variable(0.0,name='graph_w')ww=tf.Variable(tf.random_normal ...
- linux基础命令汇总
目录 linux系统结构 常用命令 切换目录命令cd 文件操作 vi和vim编辑器 重定向输出>和>> 管道 | &&命令执行控制 网络通讯命令 系统管理命令 用户和 ...
- Netty入门系列(1) --使用Netty搭建服务端和客户端
引言 前面我们介绍了网络一些基本的概念,虽然说这些很难吧,但是至少要做到理解吧.有了之前的基础,我们来正式揭开Netty这神秘的面纱就会简单很多. 服务端 public class PrintServ ...
- CSS怎么隐藏滚动条(三种方法)
xhtml中隐藏滚动条在用ie6浏览有框架的xhtml页面的时候,默认会水平和垂直滚动条会一起出现,这是ie6的一个bug,在firefox上是正常的,出现的原因是其对XHTML 1.0 transi ...