JavaScript 中虽然有对象的概念,但它并不是一门严格意义上的面向对象编程的语言。

尽管 ES6 引入了 class 关键字,但是本质上仍然是对原型链的操作。

通过修改 JavaScript 的原型,可以实现类之间的继承关系。

首先用 function 关键字定义一个 ParentClass

 1 function ParentClass(props) {
 2     this.alpha   = props.alpha || 1.0;
 3     this.color   = props.color || [0.8, 0.8, 0.8];
 4     console.log("ParentClass constructor");
 5 };
 6
 7 ParentClass.prototype = {
 8     constructor: ParentClass,
 9
10     init: function(gl) {
11         console.log("ParentClass.proptotype.init");
12     },
13
14     paint: function(gl, addon) {
15         console.log("ParentClass.proptotype.paint");
16     }
17 }

并且在 ParentClass 的原型上定义了 init 和 paint 函数。注意这里的构造器仍然是 ParentClass。

再用 function 定义 ChildClass

1 function ChildClass(props) {
2     ParentClass.call(this, props);
3     this.sides = props.sides || 24;
4     console.log("ChildClass constructor");
5 }

这里的 ParentClass 的 call 函数相当于在 ChildClass 继承了 ParentClass 之后调用 super 函数,也就是调用父类 ParentClass 的构造器。

当然这里还没有让  ChildClass 继承 ParentClass,如果调用 ChildClass 的 init 方法就会报错。

在调用 ChildClass 对象的方法时,首先就会在 ChildClass 的原型上查找是否有同名的方法,如果找不到方法,就会到原型链的上一层查找,直到 Object,

如果这个时候仍然找不到对应名称的方法,就会报错了。原型链过长的话就会影响运行速度。

要做到对象间的继承,就要修改 ChildClass 的原型链,把 ChildClass 的原型链指向 ParentClass。

这里直接给出廖雪峰的继承代码

1 /**
2   * this function is copied from liaoxuefeng's javascript tutorial
3 **/
4 inherits = function(child, parent) {
5     var F = function() {};
6     F.prototype = parent.prototype;
7     child.prototype = new F();
8     child.prototype.constructor = child;
9 }

通过一个中间函数 F,把它的原型链指向 parent 的父类,再把子类的原型改为 F 函数 new 出来的对象。child 的构造器当然还应该是 child 自己。

注意这里的 child 和 parent 应该都是指向 function 的对象(而不是用 new 关键字创造的对象)

1 inherits(ChildClass, ParentClass);  // ChildClass 继承 ParentClass

创建子类的对象

1 var child = new ChildClass({}); 

那么就会输出两行内容,分别是:

ParentClass constructor
ChildClass constructor 

再看看子类中相应的属性或方法:

1 console.log(child.alpha);  // 1
2
3 child.paint();  // ParentClass.prototype.paint

默认的 alpha 值是1,paint 继承于 ParentClass,所以分别输出 1 和 ParentClass.prototype.paint

要重写 ChildClass 的 paint 方法,直接修改原型上的 paint 属性,指向别的函数就好了:

1 ChildClass.prototype.paint = function() { console.log("ChildClass.prototpye.paint")};
2 child.paint();     // ChildClass.prototype.paint
3 ChildClass.paint;  // undefined

再调用 child.paint(),输出的就是 ChildClass.prototype.paint

关于 ChildClass 原型上的属性,只有在 new 出了对象后,由对象调用,而 ChildClass 本身是没有 paint 属性的。

再看一个例子:

1 ChildClass.testPaint = function() {console.log("ChildClass.testPaint")};
2 child = new ChildClass({});
3 child.testPaint  // undefined

如果直接给 ChildClass 添加 testPaint 属性(方法),new 出来的对象不能访问相应的属性(方法)。

那么就可以这样理解,ChildClass 原型上的属性可以被 new 出来的对象访问,相当于 Java 中类中的普通方法;

而直接在 ChildClass 上添加属性,只能被 ChildClass 访问,而不能被 new 出来的对象访问,相当于 Java 中类的静态方法。

另外,我尝试了下直接将子类(姑且这么叫吧)的原型直接指向父类的对象中,好像没有问题:

1 function SecChildClass(props) {
2     ParentClass.call(this, props);
3     this.sides = props.sides || 24;
4     console.log("SecChildClass constructor");
5 }
6
7 SecChildClass.prototype = new ParentClass({});  //  ParentClass constructor
8 SecChildClass.constructor = SecChildClass;

当然在修改 SecChildClass 的原型链,指向 ParentClass 的对象时,就会执行一遍 ParentClass 的构造器,所以这个方式确实并不好。

再看看相应对象的属性

1 var c2 = new SecChildClass({});
2 //  ParentClass constructor
3 //  SecChildClass constructor
4
5 c2.alpha;   // 1
6 c2.paint();  // ParentClass.prototype.paint

创造对象时就会输出两行内容,因为在子类的构造器里首先调用的是父类的 call 方法,所以首先执行的是父类的构造器。

值得一提的是,如果在子类的构造器中就调用 inherits 函数,传入 this 是没有用的,因为 this 指向的是子类的对象而非 ChildClass,这样的继承是没有效果的。

reference

廖雪峰 JavaScript 教程

转载于:https://www.cnblogs.com/brifuture/p/8288616.html

JavaScript 原型继承相关推荐

  1. 深入解析JavaScript 原型继承

    JavaScript 原型继承,学习js面向对象的朋友可以看看.十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. Object.prototype Ja ...

  2. 白话解释 Javascript 原型继承(prototype inheritance)

    来源: 个人博客 白话解释 Javascript 原型继承(prototype inheritance) 什么是继承? 学过"面向对象"的同学们是否还记得,老师整天挂在嘴边的面向对 ...

  3. 再论JavaScript原型继承和对象继承

    JavaScript的原型继承是老生常谈.由于原型即prototype本身也是对象,所以"原型"继承可认为是一种特殊的"对象式"继承."对象式&quo ...

  4. JavaScript原型继承详细解读

    目录 1.构造函数的简单介绍 2.构造函数的缺点 3.prototype属性的作用 4.原型链(prototype chains) 5.constructor属性 5.1:constructor属性的 ...

  5. Javascript 原型和继承(Prototypes and Inheritance)

    Javascript 原型和继承(Prototypes and Inheritance) 收藏  前面我们看到了如何使用 constructor 来初始化对象.如果这样做,那么每一个创建的新对象都会对 ...

  6. JavaScript面向对象——深入理解原型继承

    JavaScript继承--深入理解原型继承 原型继承 // 父类function School (name, address) {this.name = namethis.address = add ...

  7. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  8. JavaScript 面向对象编程(二) —— 构造函数 / 原型 / 继承 / ES5 新增方法

    本篇为 JavaScript 进阶 ES6 系列笔记第二篇,将陆续更新后续内容.参考:JavaScript 进阶面向对象 ES6 :ECMAScript 6 入门 : Javascript 继承机制的 ...

  9. JavaScript之继承(原型链)

    JavaScript之继承(原型链) 我们知道继承是oo语言中不可缺少的一部分,对于JavaScript也是如此.一般的继承有两种方式:其一,接口继承,只继承方法的签名:其二,实现继承,继承实际的方法 ...

最新文章

  1. Github上这几个沙雕项目,够我玩三天!
  2. 防火墙 之 iptables 匹配条件讲解
  3. 团队Blog功能改进
  4. 关于python2和python3除法的区别
  5. c++的ORM解决方案 -- ODB
  6. 小工匠聊架构-超高并发秒杀系统设计 05_服务端性能优化
  7. element-UI级联选择器(Cascader)获取label值 - 代码篇
  8. 【亚伦博客】反方观点: 下载不是偷窃
  9. mysql 二进制 nodejs_nodejs怎么存取2进制数据到数据库?
  10. 前端开发中最常用的JS代码片段
  11. YAF 接口 2016-10-27
  12. element 怎么把数据写到日历表上_当mongo数据量过亿时该如何删除重复的数据
  13. 神经网络训练结果都是1,神经网络训练效果不好
  14. python实现ddos防护_python实现的防DDoS脚本
  15. 11.Null和Underfined
  16. 互联网创业公司融资、产品、运营快速迭代和人才模式总结
  17. sox处理mp3_SoX — 音频处理工具里的瑞士军刀
  18. 【零基础学Python】Day13 Python函数
  19. Spring Boot+Vue(一)node.js环境搭建
  20. 物联网专题22:STA模式

热门文章

  1. FineReport中如何自定义登录界面
  2. 解决Linux动态库版本兼容问题
  3. js不停地触发按钮的事件
  4. centos --- phpunit 安装过程
  5. lamp下mysql安全加固
  6. 企业高管眼中的 SAP 和「智慧企业」| 品读中国企业数字化转型的故事
  7. 【BZOJ4720】【NOIP2016】换教室
  8. mysql 优化实例(百万级数据)
  9. Spring-AOP的五种通知和切面的优先级、通知变量声明
  10. 详解MYSQL数据库密码的加密方式及破解方法