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 tools 系列 scrollable学习
Sep 06 Javascript
jQuery选择头像并实时显示的代码
Jun 27 Javascript
如何用JavaScript实现动态修改CSS样式表
May 20 Javascript
IOS中safari下的select下拉菜单文字过长不换行的解决方法
Sep 26 Javascript
jquery实现input框获取焦点的简单实例
Jan 26 Javascript
AngularJS表格添加序号的方法
Mar 03 Javascript
详谈jQuery中的一些正则匹配表达式
Mar 08 Javascript
利用js的闭包原理做对象封装及调用方法
Apr 07 Javascript
微信小程序实现动态获取元素宽高的方法分析
Dec 10 Javascript
Vue 后台管理类项目兼容IE9+的方法示例
Feb 20 Javascript
vue路由中前进后退的一些事儿
May 18 Javascript
通过javascript实现扫雷游戏代码实例
Feb 09 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
全国FM电台频率大全 - 24 贵州省
2020/03/11 无线电
推荐一款PHP+jQuery制作的列表分页的功能模块
2014/10/14 PHP
PHP实现Session入库/存入redis的方法
2017/05/04 PHP
Laravel下生成验证码的类
2017/11/15 PHP
PHP 计算至少是其他数字两倍的最大数的实现代码
2020/05/26 PHP
javascript开发技术大全-第1章javascript概述
2011/07/03 Javascript
对frameset、frame、iframe的js操作示例代码
2013/08/16 Javascript
Ajax提交与传统表单提交的区别说明
2014/02/07 Javascript
javascript中sort()的用法实例分析
2015/01/30 Javascript
JQuery通过AJAX从后台获取信息显示在表格上并支持行选中
2015/09/15 Javascript
jQuery实现ajax无刷新分页页码控件
2017/02/28 Javascript
vue缓存的keepalive页面刷新数据的方法
2019/04/23 Javascript
Openlayers显示瓦片网格信息的方法
2020/09/28 Javascript
[03:55]DOTA2完美大师赛选手传记——LFY.MONET
2017/11/18 DOTA
[01:09:20]NB vs NAVI Supermajor小组赛A组 BO3 第二场 6.2
2018/06/03 DOTA
python多线程扫描端口示例
2014/01/16 Python
简单介绍Python的Django框架的dj-scaffold项目
2015/05/30 Python
Pycharm学习教程(4) Python解释器的相关配置
2017/05/03 Python
Python中标准库OS的常用方法总结大全
2017/07/19 Python
疯狂上涨的Python 开发者应从2.x还是3.x着手?
2017/11/16 Python
python用opencv批量截取图像指定区域的方法
2019/01/24 Python
Python3实现的反转单链表算法示例
2019/03/08 Python
django用户登录验证的完整示例代码
2019/07/21 Python
Bootstrap File Input文件上传组件
2020/12/01 HTML / CSS
教导处工作制度
2014/01/18 职场文书
静心口服夜广告词
2014/03/20 职场文书
师德师风个人反思
2014/04/28 职场文书
优秀团干部个人事迹
2014/05/29 职场文书
2014最新股权信托合同协议书
2014/11/18 职场文书
离婚协议书范本(通用篇)
2014/11/30 职场文书
辞职信怎么写
2015/02/27 职场文书
网络研修随笔感言
2015/11/18 职场文书
投资入股协议书
2016/03/22 职场文书
创业计划书之o2o水果店
2019/08/30 职场文书
tensorflow+k-means聚类简单实现猫狗图像分类的方法
2021/04/28 Python
Vscode中SSH插件如何远程连接Linux
2022/05/02 Servers