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实现漂亮的动态信息提示效果
Aug 02 Javascript
实测jquery data()如何存值
Aug 18 Javascript
火狐下table中创建form导致两个table之间出现空白
Sep 02 Javascript
Extjs中RowExpander控件的默认展开问题示例探讨
Jan 24 Javascript
JavaScript中的原型和继承详解(图文)
Jul 18 Javascript
JS继承用法实例分析
Feb 05 Javascript
jQuery实现弹出窗口中切换登录与注册表单
Jun 05 Javascript
javascript中递归函数用法注意点
Jul 30 Javascript
js实现导航栏中英文切换效果
Jan 16 Javascript
简单实现JavaScript弹幕效果
Aug 27 Javascript
JS使用正则表达式找出最长连续子串长度
Oct 26 Javascript
vue+element树组件 实现树懒加载的过程详解
Oct 21 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 feof用来识别文件末尾字符的方法
2010/08/01 PHP
linux使用crontab实现PHP执行计划定时任务
2014/05/10 PHP
PHP模块memcached使用指南
2014/12/08 PHP
推荐一本PHP程序猿都应该拜读的书
2014/12/31 PHP
php数组遍历类与用法示例
2019/05/24 PHP
javaScript对象和属性的创建方法
2007/01/15 Javascript
jq实现左侧显示图片右侧文字滑动切换效果
2015/08/04 Javascript
Javascript中的数组常用方法解析
2016/06/17 Javascript
JS+Canvas实现的俄罗斯方块游戏完整实例
2016/12/12 Javascript
JavaScript对象封装的简单实现方法(3种方法)
2017/01/03 Javascript
js中Generator函数的深入讲解
2019/04/07 Javascript
详解Vue 换肤方案验证
2019/08/28 Javascript
浅谈Node新版本13.2.0正式支持ES Modules特性
2019/11/25 Javascript
浅谈vue中$bus的使用和涉及到的问题
2020/07/28 Javascript
vue实现表格合并功能
2020/12/01 Vue.js
Vue中避免滥用this去读取data中数据
2021/03/02 Vue.js
pyramid配置session的方法教程
2013/11/27 Python
在Python中使用AOP实现Redis缓存示例
2017/07/11 Python
Python paramiko模块的使用示例
2018/04/11 Python
Python实现提取XML内容并保存到Excel中的方法
2018/09/01 Python
使用PyCharm创建Django项目及基本配置详解
2018/10/24 Python
python的set处理二维数组转一维数组的方法示例
2019/05/31 Python
python下的opencv画矩形和文字注释的实现方法
2019/07/09 Python
对python中 math模块下 atan 和 atan2的区别详解
2020/01/17 Python
Python OpenCV读取显示视频的方法示例
2020/02/20 Python
Pyecharts地图显示不完成问题解决方案
2020/05/11 Python
CSS3 真的会替代 SCSS 吗
2021/03/09 HTML / CSS
瑞士最大的图书贸易公司:Orell Füssli
2019/12/28 全球购物
医学检验专业大学生求职信
2013/11/18 职场文书
大学生社团活动总结
2014/04/26 职场文书
文明生主要事迹
2014/05/25 职场文书
投标授权委托书范文
2014/08/02 职场文书
教师考核表个人总结
2015/02/12 职场文书
2015年银行个人工作总结
2015/05/14 职场文书
Golang解析JSON对象
2022/04/30 Golang
详解Go语言中Get/Post请求测试
2022/06/01 Golang