基础3:js实现继承的多种方式
js实现继承的多种方式
1. 原型链继承
function Parent() {
this.name = 'xwk'
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()
var child = new Child()
console.log(child.getName()) // xwk
缺点:
- 引用类型的属性被所有实例共享,举个例子:
function Parent () {
this.names = ['kevin', 'daisy'];
}
function Child () {}
Child.prototype = new Parent();
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy", "yayu"]
- 在创建Child的实例时,不能向Parent传参数
- 实例丢失了自己的construct属性
2. 经典继承(借用构造函数(使用call))
function Parent() {
this.names = ["kevin", "daisy"]
}
Parent.prototype.getName = function() {
console.log(this.names)
}
function Child() {
Parent.call(this)
}
var child1 = new Child()
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy"]
缺点:Parent原型上的属性和方法不能被继承
优点:
- 在继承的时候可以向Parent传参
- 可以避免引用类型的属性被不同实例所共享
3. 组合继承
原型链继承 + 经典继承
function Parent(name) {
this.name = name
this.colors = ['red','blue']
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
var child1 = new Child('kevin', '18');
child1.colors.push('black');
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
var child2 = new Child('daisy', '20');
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]
分析下上述代码:
- Parent.call(this, name) ,解决了传参问题,并且将Parent构造函数内的属性复制到Child里,可以避免引用类型被共享;
- Child.prototype = new Parent() 同时使用原型链继承,可以保证Parent原型上的属性和方法能被Child继承到。
4. 原型式继承 (Object.create)
function createObj(obj) {
function F() {}
F.prototype = obj
return new F()
}
上述代码,其实就是ES5 Object.create 方法的实现,将传入的对象作为一个新对象的原型返回。
缺点:和原型链继承的缺点一样,引用类型的属性会被子实例所共享
var person = {
name: 'kevin',
friends: ['daisy', 'kelly']
}
var person1 = createObj(person);
var person2 = createObj(person);
person1.name = 'person1';
console.log(person2.name); // kevin
person1.friends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]
5. 寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来增强对象,最后返回对象。
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
缺点:和经典模式一样,方法都在构造函数中定义,每次创建实例都会创建一遍方法。
6. 寄生组合继承
其实就是对组合继承的优化,
我们可以看组合继承的代码,发现一共掉了两次Parent构造函数,
一次是Child.prototype = new Parent(),
一次是Child构造函数中,Parent.call(this,name),
这样导致的结果就是Child和Child.prototype中都有colors属性。
那么怎么优化呢,避免这一次重复调用呢?
如果我们不使用 Child.prototype = new Parent() ,而是间接的让 Child.prototype 访问到 Parent.prototype 呢?
function Parent(name) {
this.name = name
this.colors = ['red','blue']
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
var child1 = new Child('kevin', '18');
child1.colors.push('black');
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
var child2 = new Child('daisy', '20');
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]
注意️:
使用 Child.prototype = Object.create(Parent.prototype) 替换
Child.prototype = new Parent()
虽然目的都是一样,让Child.prototype 的原型对象 指向 Parent.prototype,
但是使用后者会把Parent构造函数内部的多余属性也继承过来,前者不会。
基础3:js实现继承的多种方式的更多相关文章
- js原生继承几种方式
js原生继承 js本身并没有继承和类的概念,本质上是通过原型链(prototype)的形式实现的. 1.先写两个构造函数Parent和Child,用于将Child继承Parent function P ...
- 23.C++- 继承的多种方式、显示调用父类构造函数、父子之间的同名函数、virtual虚函数
上章链接: 22.C++- 继承与组合,protected访问级别 继承方式 继承方式位于定义子类的”:”后面,比如: class Line : public Object //继承方式是publi ...
- JavaScript是如何实现继承的(六种方式)
大多OO语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现,下文给大家技术js实现继承的 ...
- 基础2:js创建对象的多种方式
js创建对象的多种方式 1. 工厂模式 function createPerson(name) { var o = new Object() 0.name = name return o } var ...
- 【编程题与分析题】Javascript 之继承的多种实现方式和优缺点总结
[!NOTE] 能熟练掌握每种继承方式的手写实现,并知道该继承实现方式的优缺点. 原型链继承 function Parent() { this.name = 'zhangsan'; this.chil ...
- js实现继承的5种方式 (笔记)
js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...
- js实现继承的方式总结
js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...
- js实现继承的5种方式
js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承有以下通用的几种方式1.使用对象冒充实现继承(该种实现 ...
- JS中继承方式总结
说在前面:为了使代码更为简洁方便理解, 本文中的代码均将"非核心实现"部分的代码移出. 一.原型链方式关于原型链,可点击<深入浅出,JS原型链的工作原理>,本文不再重复 ...
随机推荐
- Web 前端实战(三):雷达图
前言 在<Canvas 线性图形(五):多边形>实现了绘制多边形的函数.本篇文章将记录如何绘制雷达图.最终实现的效果是这样的: 绘制雷达图 雷达图里外层 如动图中所示,雷达图从里到外一共有 ...
- pip国内源配置
Python 的一大优点就是丰富的类库,所以我们经常会用 pip 来安装各种库,所以对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安 ...
- 【SpringSecurity系列1】基于SpringSecurity实现前后端分离无状态Rest API的权限控制
源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/01-springsecurity-state ...
- 以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化
背景 字节跳动 Data Catalog 产品早期,是基于 LinkedIn Wherehows 进行二次改造,产品早期只支持 Hive 一种数据源.后续为了支持业务发展,做了很多修修补补的工作,系统 ...
- BUUCTF-小明的保险箱
小明的保险箱 16进制打开可以发现存在一个RAR压缩包,压缩包里面应该就是flag文本 使用ARCHPR破解即可
- vue开发必须知道的小技巧
近年来,vue越来越火,使用它的人也越来越多.vue基本用法很容易上手,但是还有很多优化的写法你就不一定知道了.本文列举了一些vue常用的开发技巧.require.context() 在实际开发中,绝 ...
- orcal恢复delete误删除的数据
orcal的删除有3种:delete.truncate.drop. delete可以手动提交和回滚,且可以使用where:而truncate.drop执行即对表数据进行了修改,且不能使用where. ...
- Linux字符集和编码
计算机内部,所有信息最终都是一个二进制值形式存放 字符集 字符集:charset是character set的简写,即二进制和字符的对应关系,不关注最终的存储形式 编码 字符集编码:encoding是 ...
- word processing in nlp with tensorflow
Preprocessing Tokenizer source code:https://github.com/keras-team/keras-preprocessing/blob/master/ke ...
- Linux安装fastdfs集群部署
过程问题: make: gcc:命令未找到 解决: yum -y install gcc 一.环境和版本: Linux环境:CentOS 7.6 libfastcommon版本:1.0.39 Fast ...