概要

  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. jQuery给table中的负数标红色

    <table class="tb_list"></table> $(function(){ $(".tb_list td").each( ...

  2. JSTL与EL常用标签(转)

    JSTL与EL EL相关概念 JSTL一般要配合EL表达式一起使用,来实现在jsp中不出现java代码段.所以我们先来学习EL表达式 EL主要用于查找作用域中的数据,然后对它们执行简单操作:它不是编程 ...

  3. Cortex-M3 动态加载二(RWPI数据无关实现)

    上一篇关于动态加载讲述的是M3下面的ropi的实现细节,这一篇则讲述RW段的实现细节以及系统加载RW段的思路,我在M3上根据这个思路可以实现elf的动态加载,当然进一步的可以优化很多东西,还可以研究将 ...

  4. 树的判断(poj nyoj hduoj)

    题目: http://ac.jobdu.com/problem.php?pid=1481 http://acm.nyist.net/JudgeOnline/problem.php?pid=129 ht ...

  5. SSE && WebSockets

    SSE && WebSockets 参考 http://www.bitscn.com/school/HTMLCSS/201402/194940.html WebSockets 定义了一 ...

  6. JAVA并发,CountDownLatch使用

    该文章转自:http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html CountDownLatch 1.类介绍 一 ...

  7. Oracle数据库时间修改

    http://blog.csdn.net/tianlesoftware/article/details/6163859

  8. delphi datasnap 心跳包

    为了能让我们的服务程序更加稳定,有些细节问题必须解决.就如上一讲中提到的客户端拔掉网线,造成服务器上TCP变成死连接,如果死连接数量过多,对服务器能长期稳定运行是一个巨大的威胁.另外,经过测试,如果服 ...

  9. cocos2dx 在mac下开发ios和android游戏

    这里主要说android,因为ios开发在文章 http://blog.csdn.net/itcastcpp/article/details/24792323 中已经说过. 1)打开工程 打开ecli ...

  10. java的抽象类

    现实世界中,人们表征世界时,会把现实世界中的很多类具有相同特征的事物归为一个抽象类.比如水果是许多植物果实的总称,我们可以定义一个苹果类.定义一个西瓜类,可以实例化一个苹果对象,可以实例化一个西瓜对象 ...