概要

  JS虽然没有直接有面向对象的特性,但还是能prototype为了模拟面向对象的特性,如继承和多态。而大多数面向对象的语言(例如C++。Java等一下)相比,JS为了实现面向对象还是有点繁琐,抽象。需要对JS的prototype模式有深刻的理解。
  在开发过程中,有时候会遇到这样一个问题:假设在子类中“覆盖”了超类的某个方法,但仍须要在子类方法中调用一次超类方法,这时候应该怎么做?假设是Java,一个简单的superkeyword就可以解决这个问题,但假设是JS呢?
  解决这个问题的最基本方法能够是:在子类中,使用超类类型。通过applykeyword。以当前类实例引用运行一次超类方法。例如以下:


定义类A
// 定义类A
function A(a) {
this.a = a;
}
// 为类A定义show方法
A.prototype.show = function() {
alert("A: " + this.a);
};

定义类B并从A继承

// 定义类B
function B(a, b) {
// 调用A的构造函数
A.apply(this, arguments);
this.b = b;
}
// 链接A的原型
B.prototype = new A();


实例化类B对象并调用show方法
var b = new B(100, 200);
b.show();

  此时。会运行定义在A中的show方法(显示A.a的值)。表示类B已经从类A中继承了show方法


类B覆盖show方法
// 覆盖show方法
B.prototype.show = function() {
A.prototype.show.apply(this, arguments);
alert("B: " + this.b);
}; // 运行覆盖后的方法
b.show();

  在B的prototype中又一次定义show方法,即能够觉得B类覆盖了A类的show方法。

注意 A.prototype.show.apply(this, arguments) 这一句,实际上是利用了JS的原型特性。在B类对象中(以B类对象)运行了一次A类的show方法。

  JS特殊的动态语言特性使得“覆盖”这个语义能够随时发生。甚至能够通过操作prototype来取消”覆盖“语义,这也正是JS的灵活和强大之处。


更进一步

  通过上面的样例,能够发现,JS的”继承“,”覆盖“和”调用超类方法“尽管不难理解,但写起来仍较为繁琐,以下的代码能够简化这个流程。

(以下代码灵感部分来源于ExtJS库,部分參考自prototype库)


namespace
// 定义根命名空间
ALV = {}; // 定义注冊命名空间的方法
ALV.namespace = function(ns) {
var root = window;
var parts = ns.split(".");
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
if (!root[p]) {
root[p] = {};
}
root = root[p];
}
};

合并对象的apply方法

// 合并对象成员
ALV.apply = function(obja, objb, def) {
if (def) {
ALV.apply(obja, def);
}
if (obja && objb && typeof objb === 'object') {
for (var o in objb) {
obja[o] = objb[o];
}
}
};

定义类的方法
// 原型定义
ALV.define = function(clazz, config) {
var parts = clazz.split(".");
var root = window;
for (var i = 0; i < parts.length - 1; i++) {
root = root[parts[i]];
}
var cn = parts[parts.length - 1];
if (!root[cn]) {
root[cn] = function() {};
}
clazz = root[cn];
// 将proto对象的成员赋值给类的原型
ALV.apply(clazz.prototype, config);
return clazz;
};

定义子类并继承超类的方法
// 定义继承的方法
ALV.extend = function(base, child, proto) {
// 将超类原型赋值给类的原型
var c = ALV.define(child);
if (base && typeof base === "function") {
c.prototype = new base();
}
if (proto && typeof proto == "object") {
ALV.apply(c.prototype, proto);
} // 调用超类方法
c.prototype.callParent = function(args) {
var m;
for (var o in this) {
if (this[o] === this.callParent.caller) {
m = o;
}
}
var method = base.prototype[m];
if (method && typeof method === "function") {
method.apply(this, args);
}
};
};

  上述代码中。子类的 prototype 链接到了超类对象上。完毕了 prototype 的继承。而 callParent 方法中,通过对当前类调用方法的查找,找到方法名(m变量),再在超类的 prototype 中找到同名方法,利用超类方法的 apply 操作,在子类对象上完毕对超类方法的调用。



測试代码
// 定义命名空间
ALV.namespace("Alvin.test");
// 定义超类
ALV.define("Alvin.test.A", {
a: 100,
show: function() {
alert("A: " + this.a);
}
});
// 定义子类
ALV.extend(Alvin.test.A, "Alvin.test.B", {
a: 100,
b: 200,
show: function() {
this.callParent(arguments);
alert("B: " + this.b);
}
});
// 实例化B类对象
var b = new Alvin.test.B();
b.show();
  从測试代码中能够看到,Alvin.test.B 类继承了 Alvin.test.A 类,且覆盖了当中的 show 方法。在 B 类的 show 方法中,this.callParent(arguments) 调用完毕了对 A 类show方法的调用。

这样 B 类就可以自然地访问超类方法没有在指定到底有什么关注的超类的名称。

版权声明:本文博主原创文章,博客,未经同意不得转载。

JS于,子类调用父类的函数的更多相关文章

  1. C++/JAVA/C#子类调用父类函数情况[留存]

    时间久了就容易记不清了,特留存备用查看 c++ 1.构造函数调用   常用初始化列表  或者显示调用 1.1同一个类中构造函数调用构造函数   尽量不要这样做,因为结果不确定!避免麻烦(C++11增加 ...

  2. JavaScript中子类调用父类方法的实现

    一.前言 最近在项目中,前端框架使用JavaScript面向对象编程,遇到了诸多问题,其中最典型的问题就是子类调用父类(super class)同名方法,也就是如C#中子类中调用父类函数base.** ...

  3. python子类调用父类的方法

    python子类调用父类的方法 python和其他面向对象语言类似,每个类可以拥有一个或者多个父类,它们从父类那里继承了属性和方法.如果一个方法在子类的实例中被调用,或者一个属性在子类的实例中被访问, ...

  4. c++子类和父类成员函数重名

    子类和父类返回值参数相同,函数名相同,有virtual关键字,则由对象的类型决定调用哪个函数. 子类和父类只要函数名相同,没有virtual关键字,则子类的对象没有办法调用到父类的同名函数,父类的同名 ...

  5. Python基础-接口与归一化设计、抽象类、继承顺序、子类调用父类,多态与多态性

    一.接口与归一化设计 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 由 ...

  6. Python开发基础-Day20继承实现原理、子类调用父类的方法、封装

    继承实现原理 python中的类可以同时继承多个父类,继承的顺序有两种:深度优先和广度优先. 一般来讲,经典类在多继承的情况下会按照深度优先的方式查找,新式类会按照广度优先的方式查找 示例解析: 没有 ...

  7. python基础之继承实现原理、子类调用父类的方法、封装

    继承实现原理 python中的类可以同时继承多个父类,继承的顺序有两种:深度优先和广度优先. 一般来讲,经典类在多继承的情况下会按照深度优先的方式查找,新式类会按照广度优先的方式查找 示例解析: 没有 ...

  8. Python子类调用父类内属性的方法

    常见的就是初始化方法__init__() python中类的初始化方法是__init__(),因此父类子类的初始化方法都是这个,如果子类不实现这个函数,初始化时调用父类的初始化函数,如果子类实现这个函 ...

  9. C#中子类调用父类的实现方法

    这篇文章主要介绍了C#中子类调用父类的实现方法,通过实例逐步分析了类中初始化构造函数的执行顺序问题,有助于加深对C#面向对象程序设计的理解,需要的朋友可以参考下     本文实例讲述了C#中实现子类调 ...

随机推荐

  1. 建立一个ROS msg and srv

    msg是一个描述ROS消息字段的简单的文本文件,它们经常用来为消息产生不同语言的源代码. srv文件描述一个服务,它由请求和响应两部分组成. msg文件被存储在一个包的msg目录下,srv文件被存储在 ...

  2. zoj 3792 Romantic Value

    题目链接 求最小割的值, 以及割边最少的情况的边数. 先求一遍最小割, 然后把所有割边的权值变为1, 其他边变成inf, 在求一遍最小割, 此时求出的就是最少边数. Inf打成inf  WA了好几发. ...

  3. Linux发展历史大事编年表(截止2013年)

    这篇文章主要介绍了Linux发展历史大事编年表(截止2013年),Linux现在已经无处不在,是一个伟大的开原项目,让我一起来看看23年来它的发展历程吧   我们周围到处都有Linux的身影,在家中. ...

  4. node 上传文件 路径 重命名等问题

    最近在学习node,想做一个简单的网站.首先想到的是上传文件的功能,查了下,发现有一个formidable模块,操作方便,便拿来尝试了一下,结果很纠结. 下载安装的就不用说了,用npm即可.说一下,自 ...

  5. 理解angular中的module和injector,即依赖注入

    理解angular中的module和injector,即依赖注入 依赖注入(DI)的好处不再赘言,使用过spring框架的都知道.angularjs作为前台js框架,也提供了对DI的支持,这是java ...

  6. Android Studio 中快速提取方法

    在开发过程中,有时在一个方法内部写了过多的代码,然后想要把一些代码提取出来封装下,分离开放在一个单独的方法里,可能你的做法是直接选中后Ctrl + 叉,或者 Ctrl + C,但在Android St ...

  7. 传智播客C/C++各种开发环境搭建视频工具文档免费教程

    传智播客作为中国IT培训的领军品牌,一直把握技术趋势,给大家带来最新的技术分享!传智播客C/C++主流开发环境免费分享视频文档中,就有写一个helloworld程序的示范.火速前来下载吧 所谓&quo ...

  8. 几个学习Maven不错的网址

    几个学习Maven不错的网址:---------------------------------------------------1.Maven官方网站 http://maven.apache.or ...

  9. 最长回文子串 | 勇幸|Thinking

    最长回文子串 | 勇幸|Thinking 最长回文子串

  10. Identity Card(水题)

    Identity Card Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...