JavaScript原型继承_动力节点Java学院整理


Posted in Javascript onJune 30, 2017

在传统的基于Class的语言如Java、C++中,继承的本质是扩展一个已有的Class,并生成新的Subclass。
由于这类语言严格区分类和实例,继承实际上是类型的扩展。但是,JavaScript由于采用原型继承,我们无法直接扩展一个Class,因为根本不存在Class这种类型。

但是办法还是有的。我们先回顾Student构造函数:

function Student(props) {
  this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function () {
  alert('Hello, ' + this.name + '!');
}

以及Student的原型链:

JavaScript原型继承_动力节点Java学院整理

现在,我们要基于Student扩展出PrimaryStudent,可以先定义出PrimaryStudent

function PrimaryStudent(props) {
  // 调用Student构造函数,绑定this变量:
  Student.call(this, props);
  this.grade = props.grade || 1;
}

但是,调用了Student构造函数不等于继承了StudentPrimaryStudent创建的对象的原型是:

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Object.prototype ----> null

必须想办法把原型链修改为:

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Student.prototype ----> Object.prototype ----> null

这样,原型链对了,继承关系就对了。新的基于PrimaryStudent创建的对象不但能调用PrimaryStudent.prototype定义的方法,也可以调用Student.prototype定义的方法。
如果你想用最简单粗暴的方法这么干:
PrimaryStudent.prototype = Student.prototype;

是不行的!如果这样的话,PrimaryStudentStudent共享一个原型对象,那还要定义PrimaryStudent干啥?

我们必须借助一个中间对象来实现正确的原型链,这个中间对象的原型要指向Student.prototype。为了实现这一点,参考道爷(就是发明JSON的那个道格拉斯)的代码,中间对象可以用一个空函数F来实现:

// PrimaryStudent构造函数:
function PrimaryStudent(props) {
  Student.call(this, props);
  this.grade = props.grade || 1;
}

// 空函数F:
function F() {
}

// 把F的原型指向Student.prototype:
F.prototype = Student.prototype;

// 把PrimaryStudent的原型指向一个新的F对象,F对象的原型正好指向Student.prototype:
PrimaryStudent.prototype = new F();

// 把PrimaryStudent原型的构造函数修复为PrimaryStudent:
PrimaryStudent.prototype.constructor = PrimaryStudent;

// 继续在PrimaryStudent原型(就是new F()对象)上定义方法:
PrimaryStudent.prototype.getGrade = function () {
  return this.grade;
};

// 创建xiaoming:
var xiaoming = new PrimaryStudent({
  name: '小明',
  grade: 2
});
xiaoming.name; // '小明'
xiaoming.grade; // 2

// 验证原型:
xiaoming.__proto__ === PrimaryStudent.prototype; // true
xiaoming.__proto__.__proto__ === Student.prototype; // true

// 验证继承关系:
xiaoming instanceof PrimaryStudent; // true
xiaoming instanceof Student; // true

用一张图来表示新的原型链:

JavaScript原型继承_动力节点Java学院整理

注意,函数F仅用于桥接,我们仅创建了一个new F()实例,而且,没有改变原有的Student定义的原型链。
如果把继承这个动作用一个inherits()函数封装起来,还可以隐藏F的定义,并简化代码:

function inherits(Child, Parent) {
  var F = function () {};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
}
这个inherits()函数可以复用:
function Student(props) {
  this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function () {
  alert('Hello, ' + this.name + '!');
}

function PrimaryStudent(props) {
  Student.call(this, props);
  this.grade = props.grade || 1;
}

// 实现原型继承链:
inherits(PrimaryStudent, Student);

// 绑定其他方法到PrimaryStudent原型:
PrimaryStudent.prototype.getGrade = function () {
  return this.grade;
};

小结

JavaScript的原型继承实现方式就是:

1.定义新的构造函数,并在内部用call()调用希望“继承”的构造函数,并绑定this;
2.借助中间函数F实现原型链继承,最好通过封装的inherits函数完成;
3.继续在新的构造函数的原型上定义新方法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript-世界上误解最深的语言分析
Aug 12 Javascript
js 新浪的一个图片播放图片轮换效果代码
Jul 15 Javascript
editable.js 基于jquery的表格的编辑插件
Oct 24 Javascript
圣诞节Merry Christmas给博客添加浪漫的下雪效果基于jquery实现
Dec 27 Javascript
JavaScrip实现PHP print_r的数功能(三种方法)
Nov 12 Javascript
js与jquery获取父级元素,子级元素,兄弟元素的实现方法
Jan 09 Javascript
javascript中FOREACH数组方法使用示例
Mar 01 Javascript
在javascript中使用com组件的简单实现方法
Aug 17 Javascript
微信js-sdk分享功能接口常用逻辑封装示例
Oct 13 Javascript
详细讲解vue2+vuex+axios
May 27 Javascript
vue.js数据绑定操作详解
Apr 23 Javascript
JS面向对象实现飞机大战
Aug 26 Javascript
JavaScript之排序函数_动力节点Java学院整理
Jun 30 #Javascript
JavaScript操作文件_动力节点Java学院整理
Jun 30 #Javascript
JavaScript之生成器_动力节点Java学院整理
Jun 30 #Javascript
详解vue组件通信的三种方式
Jun 30 #Javascript
JavaScript实现瀑布流图片效果
Jun 30 #Javascript
十大 Node.js 的 Web 框架(快速提升工作效率)
Jun 30 #Javascript
vue.js移动端tab组件的封装实践实例
Jun 30 #Javascript
You might like
PHP PDO函数库详解
2010/04/27 PHP
PHP使用CURL获取302跳转后的地址实例
2014/05/04 PHP
3种php生成唯一id的方法
2015/11/23 PHP
thinkPHP模板中for循环与switch语句用法示例
2016/11/30 PHP
php获取ip及网址的简单方法(必看)
2017/04/01 PHP
Laravel 使用查询构造器配合原生sql语句查询的例子
2019/10/12 PHP
PHP 对象继承原理与简单用法示例
2020/04/21 PHP
Jquery中LigerUi的弹出编辑框(实现方法)
2013/07/09 Javascript
jquery $.each() 使用小探
2013/08/23 Javascript
JavaScript将一个数组插入到另一个数组的方法
2015/03/19 Javascript
原生js实现的贪吃蛇网页版游戏完整实例
2015/05/18 Javascript
基于jQuery+Cookie实现的防止刷新的在线考试倒计时
2015/06/19 Javascript
JavaScript数据结构与算法之集合(Set)
2016/01/29 Javascript
详解JavaScript的AngularJS框架中的表达式与指令
2016/03/05 Javascript
通过jquery-ui中的sortable来实现拖拽排序的简单实例
2016/05/24 Javascript
浅谈JavaScript 浏览器对象
2016/06/03 Javascript
JavaScript中对象的不同创建方法
2016/08/12 Javascript
关于Vue实现组件信息的缓存问题
2017/08/23 Javascript
对于js垃圾回收机制的理解
2017/09/14 Javascript
微信小程序中setInterval的使用方法
2017/09/29 Javascript
vue.js分页中单击页码更换页面内容的方法(配合spring springmvc)
2018/02/10 Javascript
浅谈对于“不用setInterval,用setTimeout”的理解
2019/08/28 Javascript
[05:29]2014DOTA2国际邀请赛 赛后专访:LGDNewbee顺利过关
2014/07/13 DOTA
python 解析XML python模块xml.dom解析xml实例代码
2014/02/07 Python
利用Python的Flask框架来构建一个简单的数字商品支付解决方案
2015/03/31 Python
Python使用Flask-SQLAlchemy连接数据库操作示例
2018/08/31 Python
植物选择:Botanic Choice
2017/02/15 全球购物
旅游管理实习自我鉴定
2013/09/29 职场文书
工程资料员岗位职责
2014/03/10 职场文书
节水标语大全
2014/06/11 职场文书
图书馆志愿者活动总结
2014/06/27 职场文书
致地震灾区的慰问信
2015/03/23 职场文书
调解书格式范本
2015/05/20 职场文书
个人催款函范文
2015/06/23 职场文书
高通2023 年将发布高性能PC处理器
2022/04/29 数码科技
Redis基本数据类型Set常用操作命令
2022/06/01 Redis