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 相关文章推荐
JavaScript高级程序设计(第3版)学习笔记11 内建js对象
Oct 11 Javascript
JavaScript 模块化编程(笔记)
Apr 08 Javascript
javascript cookie的简单应用
Feb 24 Javascript
AngularJS入门教程之表单校验用法示例
Nov 02 Javascript
vue-router路由懒加载和权限控制详解
Dec 13 Javascript
vue二级路由设置方法
Feb 09 Javascript
解决vuejs项目里css引用背景图片不能显示的问题
Sep 13 Javascript
详解关于vue2.0工程发布上线操作步骤
Sep 27 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
Feb 15 Javascript
JS 逻辑判断不要只知道用 if-else 和 switch条件判断(小技巧)
May 27 Javascript
vue根据条件不同显示不同按钮的操作
Aug 04 Javascript
原生JavaScript实现购物车
Jan 10 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模板中使用PHP函数的方法
2011/04/23 PHP
在项目中寻找代码的坏命名
2012/07/14 PHP
解析func_num_args与func_get_args函数的使用
2013/06/24 PHP
php5.3 goto函数介绍和示例
2014/03/21 PHP
ThinkPHP视图查询详解
2014/06/30 PHP
php正则表达式获取内容所有链接
2015/07/24 PHP
Laravel5.1 框架控制器基础用法实例分析
2020/01/04 PHP
File, FileReader 和 Ajax 文件上传实例分析(php)
2011/04/27 Javascript
关于JavaScript的面向对象和继承有利新手学习
2013/01/11 Javascript
Extjs优化(一)删除冗余代码提高运行速度
2013/04/15 Javascript
解决js中window.open弹出的是上次的缓存页面问题
2013/12/29 Javascript
数组Array的排序sort方法
2017/02/17 Javascript
使用Browserify来实现CommonJS的浏览器加载方法
2017/05/14 Javascript
vue 开发一个按钮组件的示例代码
2018/03/27 Javascript
VueCli3.0中集成MockApi的方法示例
2019/07/05 Javascript
Vue组件为什么data必须是一个函数
2020/06/11 Javascript
Python的Flask框架中web表单的教程
2015/04/20 Python
Python实现大文件排序的方法
2015/07/10 Python
python实现下载整个ftp目录的方法
2017/01/17 Python
Python实现爬取百度贴吧帖子所有楼层图片的爬虫示例
2018/04/26 Python
Pandas GroupBy对象 索引与迭代方法
2018/11/16 Python
HTML5 Geolocation API的正确使用方法
2018/12/04 HTML / CSS
HTML5之多线程(Web Worker)
2019/01/02 HTML / CSS
美国女孩服装购物网站:Justice
2017/03/04 全球购物
static全局变量与普通的全局变量有什么区别
2014/05/27 面试题
劳资员岗位职责
2013/11/11 职场文书
2014的自我评价
2014/01/13 职场文书
师说教学反思
2014/02/07 职场文书
四年大学自我鉴定
2014/02/17 职场文书
2014年开学第一课活动方案
2014/03/06 职场文书
竞聘演讲稿精彩开头和结尾
2014/05/14 职场文书
四风批评与自我批评发言稿
2014/10/14 职场文书
党的群众路线教育实践活动个人整改措施落实情况
2014/11/04 职场文书
2014年银行柜员工作总结
2014/11/12 职场文书
2015年考研复习计划
2015/01/19 职场文书
物业接待员岗位职责
2015/04/15 职场文书