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 相关文章推荐
JScript中的undefined和"undefined"的区别
Mar 08 Javascript
JavaScript中的类数组对象介绍
Dec 30 Javascript
网页瀑布流布局jQuery实现代码
Oct 21 Javascript
解析javascript图片懒加载与预加载的分析总结
Oct 27 Javascript
vue.js学习之vue-cli定制脚手架详解
Jul 02 Javascript
AngularJS中filter的使用实例详解
Aug 25 Javascript
使用JS和canvas实现gif动图的停止和播放代码
Sep 01 Javascript
Angular利用trackBy提升性能的方法
Jan 26 Javascript
原生JS实现循环Nodelist Dom列表的4种方式示例
Feb 11 Javascript
3种vue路由传参的基本模式
Feb 22 Javascript
bootstrap模态框关闭后清除模态框的数据方法
Aug 10 Javascript
原生js实现简单轮播图
Oct 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
笑谈配置,使用Smarty技术
2007/01/04 PHP
第二章 PHP入门基础之php代码写法
2011/12/30 PHP
PHP排序算法的复习和总结
2012/02/15 PHP
ThinkPHP的Widget扩展实例
2014/06/19 PHP
PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
2019/09/08 PHP
js或css文件后面跟参数的原因说明
2010/01/09 Javascript
jQuery+CSS 实现的超Sexy下拉菜单
2010/01/17 Javascript
服务器端的JavaScript脚本 Node.js 使用入门
2012/03/07 Javascript
超简单JS二级、多级联动的简单实例
2014/02/18 Javascript
JavaScript设计模式之工厂方法模式介绍
2014/12/28 Javascript
JavaScript 封装一个tab效果源码分享
2015/09/15 Javascript
js判断当前页面用什么浏览器打开的方法
2016/01/06 Javascript
教你如何在Node.js中使用jQuery
2016/08/28 Javascript
JS出现失效的情况总结
2017/01/20 Javascript
js常用DOM方法详解
2017/02/04 Javascript
浅谈AngularJS中使用$resource(已更新)
2017/09/14 Javascript
Ant design vue中的联动选择取消操作
2020/10/31 Javascript
[01:14:41]DOTA2-DPC中国联赛定级赛 iG vs Magma BO3第一场 1月8日
2021/03/11 DOTA
深度剖析使用python抓取网页正文的源码
2014/06/11 Python
python对配置文件.ini进行增删改查操作的方法示例
2017/07/28 Python
python爬虫 正则表达式使用技巧及爬取个人博客的实例讲解
2017/10/20 Python
python奇偶行分开存储实现代码
2018/03/19 Python
Mac下Anaconda的安装和使用教程
2018/11/29 Python
对python3新增的byte类型详解
2018/12/04 Python
python实现共轭梯度法
2019/07/03 Python
Python常用编译器原理及特点解析
2020/03/23 Python
Django 多对多字段的更新和插入数据实例
2020/03/31 Python
python gui开发——制作抖音无水印视频下载工具(附源码)
2021/02/07 Python
惠而浦美国官网:Whirlpool.com
2021/01/19 全球购物
实习护士自我鉴定
2013/10/13 职场文书
四风问题个人自查剖析材料思想汇报
2014/09/21 职场文书
教师对照四风自我剖析材料
2014/09/30 职场文书
大学生村官驻村工作心得体会
2016/01/23 职场文书
SpringBoot整合minio快速入门教程(代码示例)
2022/04/03 Java/Android
python字符串的一些常见实用操作
2022/04/06 Python
Pandas实现批量拆分与合并Excel的示例代码
2022/05/30 Python