概要

  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. std中map

    在map中需要对位置a和b值进行交换,代码如下: auto val1 = tmpMap.at(a); auto val2 = tmpMap.at(b); tmpMap.insert(std::make ...

  2. RecyclerView 小记

    RecyclerView,是在v7包加入的,一个灵活的view可以展示巨大的数据集,类似于listview的viewholder复用已经优化好了. 语言是苍白的,代码是最生动的叙说: 布局: < ...

  3. Android 中Notification的运用

    Notification在手机的运用中是很常见的,比如我们收到一个短信,在我们的通知栏就会显示一个消息的图标用来提示我们,这种我们就可以用Notification来实现.他有很多的用法,比如类似消息的 ...

  4. Windows Latex 中日文字体设置例

    中文字体例: \documentclass[CJK]{article} \usepackage{CJKutf8} \newcommand{\songti}{\CJKfamily{song}} % 宋体 ...

  5. UBER人民优步司机注册攻略

        注意:本文驾驶证行驶证图片为本人拍摄,请广大网友勿作它用 转载请修改! 详细的介绍注册优步uber司机端步骤; uber对司机的要求: 车辆为本地牌照 车龄在5年以内 裸车价格在10万以上 目 ...

  6. JWPlayer 使用小记

    最后的效果 1.从官网下载JWPlayer 下载后的文件,标红部分是必要的文件. 2.Jquery可以使用1.6以上版本 <html><head> <title>G ...

  7. 如何查看数据文件或者Log文件是否增长过?

    在论坛看到一个帖子,说数据库变慢了一段时间,发现这段时间数据库文件的最后修改时间跟变慢的世界一致,想知道这段时间是否文件确实增长了. 其实SQL Server提供了数据增长的Event,而且Defau ...

  8. [置顶] js模板方法的思路及实现

    在js中如何实现设计模式中的模板方法? 思路的产生必然要求熟悉js,如何实现?就很简单了,都知道在js中如果定义两个相同名称的方法,前一个方法就会被后一个方法覆盖掉,使用此特点就可以实现模板方法. 例 ...

  9. MYSQL++之Connect类型

    原文转自:www.cnblogs.com/aicro mysqlpp:: Connect类型主要负责连接事宜,这是在所有开始mysql操作之前必须进行的(这是句废话). 该类型的主要的结果如下所示 m ...

  10. iOS app 集成友盟推送问题

    之前做app推送主要是集成友盟SDK,在程序获取deviceToken时,老是提示如下错误: Error Domain=NSCocoaErrorDomain Code=3000 "未找到应用 ...