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 相关文章推荐
学习YUI.Ext 第四天--对话框Dialog的使用
Mar 10 Javascript
div+css布局的图片连续滚动js实现代码
May 04 Javascript
JQuery中html()方法使用不当带来的陷阱
Apr 07 Javascript
JQuery与JSon实现的无刷新分页代码
Sep 13 Javascript
JavaScript 判断浏览器是否支持SVG的代码
Mar 21 Javascript
jQuery实现从身份证号中获取出生日期和性别的方法分析
Feb 25 Javascript
jQuery图片渐变特效的简单实现
Jun 25 Javascript
js方法数据验证的简单实例
Sep 17 Javascript
通过V8源码看一个关于JS数组排序的诡异问题
Aug 14 Javascript
element-ui表格数据转换的示例代码
Aug 24 Javascript
Vue-input框checkbox强制刷新问题
Apr 18 Javascript
javascript实现京东快递单号的查询效果
Nov 30 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
再次研究下cache_lite
2007/02/14 PHP
MySQL授权问题总结
2007/05/06 PHP
php function用法如何递归及return和echo区别
2014/03/07 PHP
Dwz与thinkphp整合下的数据导出到Excel实例
2014/12/04 PHP
Yii2使用dropdownlist实现地区三级联动功能的方法
2016/07/18 PHP
php获取ajax的headers方法与内容实例
2017/12/27 PHP
PHP数组基本用法与知识点总结
2020/06/02 PHP
js字符编码函数区别分析
2008/06/05 Javascript
javascript闭包的理解和实例
2010/08/12 Javascript
浅析js封装和作用域
2013/07/09 Javascript
JQuery页面的表格数据的增加与分页的实现
2013/12/10 Javascript
js打开windows上的可执行文件示例
2014/05/27 Javascript
jQuery中:button选择器用法实例
2015/01/04 Javascript
javascript实现连续赋值
2015/08/10 Javascript
js解决movebox移动问题
2016/03/29 Javascript
JS函数多个参数默认值指定方法分析
2016/11/28 Javascript
使用vue实现点击按钮滑出面板的实现代码
2017/01/10 Javascript
nodejs入门教程五:连接数据库的方法分析
2017/04/24 NodeJs
Three.js中网格对象MESH的属性与方法详解
2017/09/27 Javascript
[44:58]2018DOTA2亚洲邀请赛 4.5 淘汰赛 LGD vs Liquid 第二场
2018/04/06 DOTA
python代码 if not x: 和 if x is not None: 和 if not x is None:使用介绍
2016/09/21 Python
Unicode和Python的中文处理
2017/03/19 Python
python3 BeautifulSoup模块使用字典的方法抓取a标签内的数据示例
2019/11/28 Python
pytorch 获取tensor维度信息示例
2020/01/03 Python
Python函数必须先定义,后调用说明(函数调用函数例外)
2020/06/02 Python
CSS3中background-clip和background-origin的区别示例介绍
2014/03/10 HTML / CSS
美国受欢迎的眼影品牌:BH Cosmetics
2016/10/25 全球购物
俄罗斯旅游网站:Tripadvisor俄罗斯
2017/03/21 全球购物
如何用JQuery进行表单验证
2013/05/29 面试题
Java的类可以定义为Protected或者Private得吗
2015/09/25 面试题
环境科学专业个人求职的自我评价
2013/11/28 职场文书
青年安全生产示范岗事迹材料
2014/05/04 职场文书
会计系毕业生求职信
2014/05/28 职场文书
县委常委班子专题民主生活会查摆问题及整改措施
2014/09/27 职场文书
查摆问题整改措施范文
2014/10/11 职场文书
opencv 分类白天与夜景视频的方法
2021/06/05 Python