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 相关文章推荐
jquery键盘事件介绍
Jan 31 Javascript
javascript使用call调用微信API
Dec 15 Javascript
Jquery实现弹性滑块滑动选择数值插件
Aug 08 Javascript
jQuery实现的简单分页示例
Jun 01 Javascript
JavaScript语言精粹经典实例(整理篇)
Jun 07 Javascript
JS实现HTML表格排序功能
Aug 05 Javascript
JS获取当前页面名称的简单实例
Aug 19 Javascript
AngularJS指令与控制器之间的交互功能示例
Dec 14 Javascript
BootStrap 获得轮播中的索引和当前活动的焦点对象
May 11 Javascript
javaScript之split与join的区别(详解)
Nov 08 Javascript
vue+springboot实现项目的CORS跨域请求
Sep 05 Javascript
OpenLayers3加载常用控件使用方法详解
Sep 25 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
9个PHP开发常用功能函数小结
2011/07/15 PHP
Yii框架数据库查询、增加、删除操作示例
2019/10/14 PHP
js制作的鼠标悬浮时产生的下拉框效果
2012/10/27 Javascript
JS.getTextContent(element,preformatted)使用介绍
2013/09/21 Javascript
JS小功能(offsetLeft实现图片滚动效果)实例代码
2013/11/28 Javascript
基于JavaScript实现Json数据根据某个字段进行排序
2015/11/24 Javascript
js密码强度检测
2016/01/07 Javascript
使用vue.js开发时一些注意事项
2016/04/27 Javascript
JS闭包与延迟求值用法示例
2016/12/22 Javascript
详解照片瀑布流效果(js,jquery分别实现与知识点总结)
2017/01/01 Javascript
JavaScript中从setTimeout与setInterval到AJAX异步
2017/02/13 Javascript
bootstrap fileinput 插件使用项目总结(经验)
2017/02/22 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
2017/07/27 Javascript
深入浅出es6模板字符串
2017/08/26 Javascript
JS实现的input选择图片本地预览功能示例
2018/08/29 Javascript
微信小程序开发之tabbar图标和颜色的实现
2018/10/17 Javascript
详解Vue中使用插槽(slot)、聚类插槽
2019/04/12 Javascript
vue 页面回退mounted函数不执行的解决方案
2020/07/26 Javascript
vue组件开发之slider组件使用详解
2020/08/21 Javascript
在Vue中使用Select选择器拼接label的操作
2020/10/22 Javascript
[01:08:43]DOTA2-DPC中国联赛定级赛 Phoenix vs DLG BO3第一场 1月9日
2021/03/11 DOTA
python实现基于两张图片生成圆角图标效果的方法
2015/03/26 Python
python的Tqdm模块的使用
2018/01/10 Python
unittest+coverage单元测试代码覆盖操作实例详解
2018/04/04 Python
pip安装提示Twisted错误问题(Python3.6.4安装Twisted错误)
2020/05/09 Python
HTML5 video视频字幕的使用和制作方法
2018/05/03 HTML / CSS
HTML5是否真的可以取代Flash
2010/02/10 HTML / CSS
DJI大疆德国官方商城:大疆无人机
2018/09/01 全球购物
英国第一的市场和亚马逊替代品:OnBuy
2019/03/16 全球购物
接口可以包含哪些成员
2012/09/30 面试题
营销专业应届生求职信
2013/11/26 职场文书
数控专业毕业生自荐信范文
2014/03/04 职场文书
2014年设计师工作总结
2014/11/25 职场文书
银行员工考核评语
2014/12/31 职场文书
作息时间调整通知
2015/04/22 职场文书
2015年党风廉政建设个人总结
2015/08/18 职场文书