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 实现的全选和反选
Apr 15 Javascript
JavaScript 构造函数 面相对象学习必备知识
Jun 09 Javascript
jQuery 阴影插件代码分享
Jan 09 Javascript
JavaScript获取网页表单action属性的方法
Apr 02 Javascript
jQuery选择器用法实例详解
Dec 17 Javascript
BootStrap Validator对于隐藏域验证和程序赋值即时验证的问题浅析
Dec 01 Javascript
Vue.js实战之利用vue-router实现跳转页面
Apr 01 Javascript
javascript数据结构中栈的应用之符号平衡问题
Apr 11 Javascript
最常用的jQuery表单验证(简单)
May 23 jQuery
解决vue this.$forceUpdate() 处理页面刷新问题(v-for循环值刷新等)
Jul 26 Javascript
详解vue更改头像功能实现
Apr 28 Javascript
在Chrome DevTools中调试JavaScript的实现
Apr 07 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数组无限分级数据的层级化处理代码
2012/12/29 PHP
php MessagePack介绍
2013/10/06 PHP
PHP延迟静态绑定示例分享
2014/06/22 PHP
YII路径的用法总结
2014/07/09 PHP
图文介绍PHP添加Redis模块及连接
2015/07/28 PHP
如何使用GDB调试PHP程序
2015/12/08 PHP
功能强大的php文件上传类
2016/08/29 PHP
php分页查询mysql结果的base64处理方法示例
2017/05/18 PHP
safari,opera嵌入iframe页面cookie读取问题解决方法
2010/06/23 Javascript
根据对象的某一属性进行排序的js代码(如:name,age)
2010/08/10 Javascript
有趣的javascript数组定义方法
2010/09/10 Javascript
Tab切换组件(选项卡功能)实例代码
2013/11/21 Javascript
jQuery定义插件的方法
2015/12/18 Javascript
js Canvas绘制圆形时钟教程
2017/02/06 Javascript
微信小程序中form 表单提交和取值实例详解
2017/04/20 Javascript
ReactJS实现表单的单选多选和反选的示例
2017/10/13 Javascript
3种vue路由传参的基本模式
2018/02/22 Javascript
AjaxUpLoad.js实现文件上传
2018/03/05 Javascript
boostrap模态框二次弹出清空原有内容的方法
2018/08/10 Javascript
jQuery实现checkbox全选、反选及删除等操作的方法详解
2019/08/02 jQuery
Python实现的飞速中文网小说下载脚本
2015/04/23 Python
部署Python的框架下的web app的详细教程
2015/04/30 Python
Python for Informatics 第11章之正则表达式(二)
2016/04/21 Python
Python输出由1,2,3,4组成的互不相同且无重复的三位数
2018/02/01 Python
spark dataframe 将一列展开,把该列所有值都变成新列的方法
2019/01/29 Python
将python文件打包成EXE应用程序的方法
2019/05/22 Python
在pytorch中查看可训练参数的例子
2019/08/18 Python
浅谈Python_Openpyxl使用(最全总结)
2019/09/05 Python
浅析python中while循环和for循环
2019/11/19 Python
实现strstr功能,即在父串中寻找子串首次出现的位置
2016/08/05 面试题
VLAN和VPN有什么区别?分别实现在OSI的第几层?
2014/12/23 面试题
通信工程毕业生求职信
2013/11/16 职场文书
党员对照检查材料思想汇报(党的群众路线)
2014/09/24 职场文书
学习保证书怎么写
2015/02/26 职场文书
免职通知
2015/04/23 职场文书
导游词之河北野三坡
2019/12/11 职场文书