ES5中的继承
继承
在面向对象的语言中, 大多语言都支持两种继承方式: 接口继承
和 实现继承
, 接口继承
只继承方法签名, 实现继承
才继承实际的方法, ECMAScript
值支持 实现继承
, 今天我们来谈谈实现继承的几种方式
原型链
关于原型链的知识我们前面已经介绍过了, 详情请见 原型链, 在 js 中原型链是实现继承的主要方法, 实现原理是利用原型链让一个引用类型继承另一个引用类型的属性和方法, 在阅读此章节需要对前面的原型有较深的理解, 而且最好能够清晰的描述出 js 中几大引用类型构造器之间的原型链, 现在来看个 Demo
let Car = function(brand) {
this.brand = brand;
};
Car.prototype.getBrand = function() {
console.log(this.brand);
};
let Ferrari = function() {
this.brand = 'ferrari';
}
// 实现继承
Ferrari.prototype = new Car('rover');
let inst = new Ferrari();
inst.getBrand(); //ferrari
console.log(inst instanceof Car); // true
这里需要说明一下, instanceof
只要实例的原型链中出现的构造器都会返回 true
, 使用字面量和使用拓展的形式 Ferrari.prototype = new Car('rover')
VS Ferrari.prototype.getBrand = new Car('rover')
两种方式存在一些差别, 前者是重写了子类的原型, 也就是说子类原型的内存地址已经发生了变化, 这有会导致原来的实例全部丢失与现在的原型的联系, 后者是拓展子类的原型, 并不会导致切断原来的实例与现在的原型的联系, 因为子类的原型还是原来内存中的那个对象, 并不只是原型链继承才会出现这样的差别, 这是 js 语言导致的, 堆内存
本身就具有这样的特性. 其实原型继承还存在一个缺点, 那就是当原型链里有引用类型的值的时候会出现一些问题, 请看 Demo
let Car = function(brand) {
this.options = {
color: 'red'
};
};
let Ferrari = function() {};
// 实现继承
Ferrari.prototype = new Car();
let ferrari1 = new Ferrari();
ferrari1.options.price = '$100';
let ferrari2 = new Ferrari();
console.log(ferrari2.options.price); // $100
原型链中有引用类型的值时修改该值时会影响到其他实例, 这不是我们希望看到的
借用构造函数
实现思路: 在子类里借用父类的构造器来实现, Demo 如下
let Car = function(brand) {
this.options = {
color: 'red'
};
};
let Ferrari = function() {
Car.call(this);
};
// 实现继承
Ferrari.prototype = new Car();
let ferrari1 = new Ferrari();
ferrari1.options.price = '$100';
let ferrari2 = new Ferrari();
console.log(ferrari2.options.price); // undefined
构造函数继承也存在一些问题, 比如 当继承方法时, 我们希望这些实例全部共享一个方法, 但是借用构造函数这种继承方式, 所有的继承都发生在构造函数内部, 那么每次创建一个实例都会重新创建一个方法(内存地址不同), 这样就导致了代码复用率降低
组合继承
实现思路, 使用原型链继承实现原型属性和方法的继承, 借用构造函数实现实例属性的继承
let Car = function(brand) {
this.options = {
color: 'red'
};
};
Car.prototype.getOptions = function() {
console.log(Object.keys(this.options));
};
// 实现继承
let Ferrari = function() {
Car.call(this);
};
Ferrari.prototype = new Car();
let ferrari1 = new Ferrari();
ferrari1.options.price = '$100';
ferrari1.getOptions() // ['color', 'price']
let ferrari2 = new Ferrari();
ferrari2.getOptions() // ['color']
这种继承方式避免了原型链继承和借用构造函数的缺点, 融合了它们的优点, 是最常用的继承方式
原型式继承
如果只是在两个对象之间实现继承, 我们可以考虑使用该方法
let object = (o) {
function F() {};
F.prototype = o;
return new F();
};
// 本质上 `object` 只是对传入的对象进行了一次浅复制
let ferrari = {
color: 'red'
};
let myCar = object(ferrari);
console.log(myCar.color); // red
在 ES5
中有一个方法叫 Object.create()
实现了相似的行为
寄生式继承
这种继承是和原型式继承紧密相关的一种继承方式, 也是运用于对象之间的继承
let copy = function(o) {
let clone = Object.create(o);
clone.getColor = function() {
console.log(this.color);
};
};
let ferrari = {
color: 'red'
};
let myCar = copy(ferrari);
myCar.getColor(); // red
寄生组合式继承
前面谈到的 组合式继承
已经相当完美, 但是还有一点瑕疵, 就是父函数会有一次没必要的调用
let Car = function(brand) {
this.options = {
color: 'red'
};
};
Car.prototype.getOptions = function() {
console.log(Object.keys(this.options));
};
// 实现继承
let Ferrari = function() {
Car.call(this); // 第2次调用
};
Ferrari.prototype = new Car(); 第1次调用
let ferrari1 = new Ferrari();
ferrari1.options.price = '$100';
ferrari1.getOptions() // ['color', 'price']
我们对其进行一次改造, 减少一次调用, Demo如下
let extendsSuper = function(sub, superFunc) {
let proto = Object.create(superFunc.prototype);
proto.constructor = sub;
sub.prototype = proto;
};
let Car = function(brand) {
this.options = {
color: 'red'
};
};
Car.prototype.getOptions = function() {
console.log(Object.keys(this.options));
};
// 实现继承
let Ferrari = function() {
Car.call(this);
};
extendsSuper(Ferrari, Car); // 在此减少了调用父函数次数
let ferrari1 = new Ferrari();
ferrari1.options.price = '$100';
ferrari1.getOptions() // ['color', 'price']
小结
- 在实现两个构造器之间的继承时我们推荐使用
组合继承
和寄生式组合继承
- 在实现两个对象之间的继承我们推荐使用
原型式继承
(可以使用ES5
的Object.create()
) 和寄生式继承
ES5中的继承的更多相关文章
- ES6中的类继承和ES5中的继承模式详解
1.ES5中的继承模式 我们先看ES5中的继承. 既然要实现继承,首先我们得要有一个父类. Animal.prototype.eat = function(food) { console.log(th ...
- 《前端之路》- TypeScript (三) ES5 中实现继承、类以及原理
目录 一.先讲讲 ES5 中构造函数(类)静态方法和多态 1-1 JS 中原型以及原型链 例子一 1-2 JS 中原型以及原型链中,我们常见的 constructor.prototype.**prot ...
- 彻底理解什么是原型链,prototype和__proto__的区别以及es5中的继承
再讲一遍好了( 参考https://blog.csdn.net/cc18868876837/article/details/81211729 https://blog.csdn.net/lc23742 ...
- ES5和ES6中的继承 图解
Javascript中的继承一直是个比较麻烦的问题,prototype.constructor.__proto__在构造函数,实例和原型之间有的 复杂的关系,不仔细捋下很难记得牢固.ES6中又新增了c ...
- ES5和ES6中的继承
看到一篇写的非常好的关于js继承的文章,其中对构造函数.原型.实例之间的关系的描述十分透彻,故转载作者文章以随时学习,并供大家共同进步! ES5 ES5中的继承,看图: function Super( ...
- 浅谈ES5和ES6继承和区别
最近想在重新学下ES6,所以就把自己学到的,记录下加强下自己的理解 首先先简单的聊下ES5和ES6中的继承 1.在es5中的继承: function parent(a,b){ this a = a; ...
- ES5和ES6中对于继承的实现方法
在ES5继承的实现非常有趣的,由于没有传统面向对象类的概念,Javascript利用原型链的特性来实现继承,这其中有很多的属性指向和需要注意的地方. 原型链的特点和实现已经在之前的一篇整理说过了,就是 ...
- Es5中的类和静态方法 继承
Es5中的类和静态方法 继承(原型链继承.对象冒充继承.原型链+对象冒充组合继承) // es5里面的类 //1.最简单的类 // function Person(){ // this.name='张 ...
- ES5与ES6中的继承
ES5继承在ES5中没有类的概念,所以一般都是基于原型链继承,具体的继承方法有以下几种: 父类: function Father (name) { this.name = name || 'sam' ...
随机推荐
- ansj分词器使用记录
//最简单实例 String ruiec = “分词测试123456100名”; //剔除指定的分词 s.insertStopWords("100名"); //剔除标点符号(w) ...
- 【crontab】误删crontab及其恢复
中秋节快到了,首先祝自己中秋快乐. 昨天下午六点,心里正想着加完一个crontab就可以下班了.本来想执行 crontab -e的,没想到手一抖就输入了crontab ,然后就进入了下面这个样子.
- Win10看图总有遮挡?如何找回好用的照片查看器
来,大家日常在电脑上查看图片是用什么软件?老牌的ACDSee.XXX看图王.美图看看还是Win系统自带的呢?反正小编在没什么特殊需要的时候,只用系统自带,免除安装.功能够用,想要进行处理也能用Win自 ...
- TypeScript作为前端开发你必须学习的技能(三)
TypeScript 运算符 TypeScript 主要包含以下几种运算: 算术运算符 逻辑运算符 关系运算符 按位运算符 赋值运算符 三元/条件运算符 字符串运算符 类型运算符 实例看图: 关系运算 ...
- 8.django单独执行文件
import os import django # 导入django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'noju.settings')d ...
- node中controller的get和post方法获取参数
1.get: const body = ctx.query; // get请求 2.post: const body = ctx.request.body; // post请求
- #381 Div2 Problem C Alyona and mex (思维 && 构造)
题意 : 题目的要求是构造出一个长度为 n 的数列, 构造条件是在接下来给出的 m 个子区间中, 要求每一个子区间的mex值最大, 然后在这 m 个子区间产生的mex值中取最小的输出, 并且输出构造出 ...
- 51Nod 1413 权势二进制 (思维)
题意 : 一个十进制整数被叫做权势二进制, 当他的十进制表示的时候只由0或1组成.例如0, 1, 101, 110011都是权势二进制而2, 12, 900不是.当给定一个n (1<=n< ...
- You Only Look Once Unified, Real-Time Object Detection(你只需要看一次统一的,实时的目标检测)
我们提出了一种新的目标检测方法YOLO.先前的目标检测工作重新利用分类器来执行检测.相反,我们将目标检测作为一个回归问题来处理空间分离的边界框和相关的类概率.单个神经网络在一次评估中直接从完整图像预测 ...
- 随堂小测APP使用体验
随堂小测APP使用体验 先要去注册账号需要填写用户名.密码.手机号.学号/教师号.学校.专业.即可注册,注册成功后,即可登录APP进,登陆进去以后.会有两个界面,课堂和我的,注册.登录简单,通俗易懂, ...