`

13、JavaScript继承实现(二) —— zInherit、xbObjects

阅读更多
  • zInherit

利用zInherit库(可以从http://www.nczonline.net/downloads 处下载),不必使用原型链,也可实现方法继承。
Inherit库给Object类添加了两个方法,inheritFrom()和instanceOf()。inheritFrom()方法负担重任,负责复制指定类的所有方法。下面一行代码用原型链使ClassB继承ClassA的方法:
ClassB.prototype = new ClassA();
可用下面代码替换上面的代码:
ClassB.prototype.inheritFrom(ClassA);
inheritFrom() 方法接受一个参数,即要复制的方法所属的类。注意,与原型链相对的是,这种方式并未真正创建要继承的类的实例(具体请参考zInherit源码),这样更安全,开发者也无需担心构造函数的参数。

instanceOf() 方法是instanceof运算符的替代品。因为这种方式根本不使用原型链,所以这行代码无效:
base3 instanceof Base1
但instanceOf()方法弥补了这项损失,与inheritFrom()一起使用,可以跟踪所有的超类:
base3.instanceOf(Base1);

zInherit多层继承具体示例代码如下:

function Base1(base1Name) {    
    this.base1Name = base1Name;    
    if (typeof Base1._initialized == "undefined") {    
        Base1.prototype.getBase1 = function () {    
            alert(this.base1Name);    
        };    
        Base1._initialized = true;    
    }    
}     
//Base2继承Base1     
function Base2(base1Name, base2Name) {    
    this.base2Name = base2Name;     
    //使用call方式对属性继承     
    Base1.call(this, base1Name);    
    if (typeof Base2._initialized == "undefined") {     
        //使用zinherit方式对方法时行复制继承     
        Base2.prototype.inheritFrom(Base1);    
        Base2.prototype.getBase2 = function () {    
            alert(this.base2Name);    
        };    
        Base2._initialized = true;    
    }    
}     
//Base3继承Base2     
function Base3(base1Name, base2Name, base3Name) {    
    this.base3Name = base3Name;     
    //使用call方式对属性继承    
    Base2.call(this, base1Name, base2Name);    
    if (typeof Base3._initialized == "undefined") {     
        //使用zinherit方式对方法时行复制继承     
        Base3.prototype.inheritFrom(Base2);    
        Base3.prototype.getBase3 = function () {    
            alert(this.base3Name);    
        };    
        Base3._initialized = true;    
    }    
}    
var base3 = new Base3("base1Name", "base2Name", "base3Name");     
//Base3可以访问从父类Base2继承过来的方法     
base3.getBase2();//base2Name    
//Base3可以访问从超类Base1继承过来的方法     
base3.getBase1();//base1Name     
//当然更可以访问自己的方法     
base3.getBase3();//base1Name    
//因为zinherit方式未采用原型链的方法,所以不支持instanceof     
alert(base3 instanceof Base1);//false    
//但可以用zinherit的instanceOf方法来避免该问题     
alert(base3.instanceOf(Base1));//true     
alert(base3.instanceOf(Base2));//true     
alert(base3.instanceOf(Base3));//true    

另外:原型链不能实现动态原型主旨,即把类的所有代码放置在它的构造函数中。zInherit库修正了这个问题,它允许在构造函数内部调用 inheritFrom()方法,使用inheritFrom()方法时,并未重写prototype对象,只是为其加入方法而已(从zInherit源码分析可知)。使用这种方法,即可避开原型链的限制,实现动态原型本意。所以zInherit支持动态原型,从上面的示例就可以看得出来。

 

zInherit的另一个好处就是除了支持多层继承、动态原型法,还支持多重继承,即一个类可以继承多个类,这些类是同一级别的。

zInherit多重继承示例如下,显示的结果与多层继承一样:  

function Base1(base1Name) {    
    this.base1Name = base1Name;    
    if (typeof Base1._initialized == "undefined") {    
        Base1.prototype.getBase1 = function () {    
            alert(this.base1Name);    
        };    
        Base1._initialized = true;    
    }    
}    
function Base2(base2Name) {    
    this.base2Name = base2Name;    
    if (typeof Base2._initialized == "undefined") {    
        Base2.prototype.getBase2 = function () {    
            alert(this.base2Name);    
        };    
        Base2._initialized = true;    
    }    
}     
//多重继承:Base3继承Base1与Base2     
function Base3(base1Name, base2Name, base3Name) {    
    this.base3Name = base3Name;     
    //使用call方式对属性继承     
    Base1.call(this, base1Name);    
    Base2.call(this, base2Name);    
    if (typeof Base3._initialized == "undefined") {    
        //使用zinherit方式对方法时行复制继承     
        Base3.prototype.inheritFrom(Base1);    
        Base3.prototype.inheritFrom(Base2);    
        Base3.prototype.getBase3 = function () {    
            alert(this.base3Name);    
        };    
        Base3._initialized = true;    
    }    
}    
var base3 = new Base3("base1Name", "base2Name", "base3Name");     
//Base3可以访问从父类Base2继承过来的方法     
base3.getBase2();//base2Name    
//Base3可以访问从超类Base1继承过来的方法     
base3.getBase1();//base1Name    
//当然更可以访问自己的方法     
base3.getBase3();//base3Name    
//因为zinherit方式未采用原型链的方法,所以不支持instanceof     
alert(base3 instanceof Base1);//false    
//但可以用zinherit的instanceOf方法来避免该问题     
alert(base3.instanceOf(Base1));//true     
alert(base3.instanceOf(Base2));//true     
alert(base3.instanceOf(Base3));//true    

 

zinherit.js源码分析

/**    
* Inherits properties and methods from the given class.    
* @scope public    
* @param fnClass The constructor function to inherit from.    
*/   
Object.prototype.inheritFrom = function (fnClass) {    
    /**    
    * Inherits all classes going up the inheritance chain recursively.    
    * @param fnClass The class to inherit from.    
    * @param arrClasses The array of classes to build up.    
    * @scope private    
    */   
    function inheritClasses(fnClass, arrClasses) {    
        /*   
        把父类构造函数放入到子类构造函数的私有属性数组中,用数组实现多继承,即可以继承多个。   
        此数组里最后存放了所有父类及超类的构造函数,如果子类继承了多个类,则此数组会存储多个构造函数。    
        */   
        arrClasses.push(fnClass);    
        //如果父类构造函数继承了其他类,则递归,这样可以实现多层继承     
        if (typeof fnClass.__superclasses__ == "object") {    
            for (var i = 0; i < fnClass.__superclasses__.length; i++) {    
                //fnClass.__superclasses__[i]为父类的构造函数,如果父类继承了多个类,    
                //则fnClass.__superclasses__.length会大于1     
                inheritClasses(fnClass.__superclasses__[i], arrClasses);    
            }    
        }    
    }     
    //this为子类构造函数的原型    
    //this.constructor为子类构造函数    
    //this.constructor.__superclasses__为子类构造函数的私有属性数组     
    if (typeof this.constructor.__superclasses__ == "undefined") {     
        //这里的数组用来实现instanceOf用的     
        this.constructor.__superclasses__ = new Array();    
    }     
    //fnClass为父类构造函数     
    inheritClasses(fnClass, this.constructor.__superclasses__);    
      
    //----上面的操作是为了instanceOf方法应用设计的,下面才是方法继承    
    //把父类原型里存储的方法复制到子类构造函数原型中(注:这里是方法地址的复制),而不是真真的方法复制     
    for (prop in fnClass.prototype) {    
        if (typeof fnClass.prototype[prop] == "function") {     
            //this为子类构造函数的原型实例,这里把父类原型实例中的属性(一般指方法属性,但不排除字    
            //段属性)一一复制到子类构造函数的原型实例中去。而不是采用原型链的方式:Base3.prototype=new Base2();     
            this[prop] = fnClass.prototype[prop];    
        }    
    }    
};    
/**    
   * Determines if the given object is an instance of a given class.    
   * This method is necessary because using {@link #inheritFrom} renders    
   * the JavaScript <code>instanceof</code> operator useless.    
   * @param fnClass The constructor function to test.    
   * @return True if the object is an instance of the class, false if not.    
   * @scope public    
   */   
Object.prototype.instanceOf = function (fnClass) {     
   //如果是base3.instanceOf(Base3)时     
    if (this.constructor == fnClass) {    
        return true;     
    //如果是采用zinherit继承方式时,则this.constructor.__superclasses__为数组对象     
    } else {    
        if (typeof this.constructor.__superclasses__ == "object") {     
            //再进一步判断,如:调用base3.instanceOf(Base1)时     
            for (var i = 0; i < this.constructor.__superclasses__.length; i++) {    
                if (this.constructor.__superclasses__[i] == fnClass) {    
                    return true;    
                }    
            }    
            return false;    
        } else {    
            return false;    
        }    
    }    
};   
  • xbObjects

Netscape 公司的 Bob Clary 2001 Netscape 6 Mozilla 0.6 )发布时编写而成。它支持从那时起的所有 Mozilla 版本及其他现代浏览器( IE Opera Safari )。可以从 http://archive.bclary.com/xbProjects-docs/xbObject/ 处下载。

 

   支持继承,还支持方法的重载和调用超类方法的能力。

   

 第一步必须注册,此时,需定义它是由哪个类继承而来:

这里,子类和超类名都以字符串形式传进来,而不是指向它们的构造函数的指针这个调用必须放在指定子类的构造 函数前

 如果新的类未继承任何类,调用 registerClass() 时也可以只用第一个参数。

<script type="text/javascript"></script>

 

 

第二步 ,在构造函数内调用 defineClass() 方法 ,传给它类名及被 Clary 称为 原型函数 prototype function )的指针,该函数用于初始化对象的所有属性和方法 ,例如:

  

第三步为该类创建 init() 方法 。该方法负责设置该类的所有属性 ,它必须接受与构造函数相同的参数。作为一种规定, init() 方法总是在 defineClass() 方法后调用 。例如:

init() 方法中调用的 parentMethod() 方法。 xbObjects 以这种方式允许类调用它的超类的方法 parentMethod() 方法接受任意多个参数,但第一个参数总是要调用的父类方法的名字(该参数必须是字符串,而不是函数指针),所有其他参数都被传给父类的方法。

在这个例子中,首先调用 init() 方法,这是 xbObjects 运行所必需的。即使 ClassA 未注册超类, xbObejcts 都会为它创建一个所有类的默认超类,即超类方法 init() 所属的类。

 

第四步 也是最后一步,在原型函数内添加其他类的方法

xbObjects多层继承示例如下:     

//注册类     
_classes.registerClass("Base1");    
function Base1(base1Name) {     
    //基于原型来初始化类的属性与方法     
    function prototypeFunction() {     
        //init方法设置该类的所有属性,它必须接收与构造函数相同的参数签名     
        Base1.prototype.init = function (base1Name) {     
            //...     
            this.parentMethod("init");    
            this.base1Name = base1Name;    
        };     
        //设置方法     
        Base1.prototype.getBase1 = function () {    
            alert(this.base1Name);    
        };    
    }     
    //定义类,用来初始化对象所有属性与方法     
    _classes.defineClass("Base1", prototypeFunction);    
    this.init(base1Name);    
}     
//Base2继承Base1     
_classes.registerClass("Base2", "Base1");    
function Base2(base1Name, base2Name) {    
    function prototypeFunction() {     
        //init方法接收与构造函数相同的参数签名     
        Base2.prototype.init = function (base1Name, base2Name) {    
            //...     
            this.parentMethod("init", base1Name);    
            this.base2Name = base2Name;    
        };     
        //设置方法     
        Base2.prototype.getBase2 = function () {    
            alert(this.base2Name);    
        };    
    }     
    //定义类,用来初始化对象所有属性与方法     
    _classes.defineClass("Base2", prototypeFunction);    
    this.init(base1Name, base2Name);    
}     
//Base3继承Base2     
_classes.registerClass("Base3", "Base2");    
function Base3(base1Name, base2Name, base3Name) {    
    function prototypeFunction() {    
        Base3.prototype.init = function (base1Name, base2Name, base3Name) {     
            //...     
            this.parentMethod("init", base1Name, base2Name);    
            this.base3Name = base3Name;    
        };     
        //设置方法     
        Base3.prototype.getBase3 = function () {    
            alert(this.base3Name);    
        };    
    }     
    //定义类,用来初始化对象所有属性与方法     
    _classes.defineClass("Base3", prototypeFunction);    
    this.init(base1Name, base2Name, base3Name);    
}    
var base3 = new Base3("base1Name", "base2Name", "base3Name");     
//Base3可以访问从父类Base2继承过来的方法     
base3.getBase2();//base2Name    
//Base3可以访问从超类Base1继承过来的方法     
base3.getBase1();//base1Name    
//当然更可以访问自己的方法     
base3.getBase3();//base3Name    
//因为xbObjects方式未采用原型链的方法,所以不支持instanceof     
alert(base3 instanceof Base1);//false    
//但可以用zinherit的instanceOf方法来避免该问题     
alert(base3.isInstanceOf(Base1));//true     
alert(base3.isInstanceOf(Base2));//true     
alert(base3.isInstanceOf(Base3));//true    

 

注:上面this.parentMethod("init"...)前最好不要加上中文注释,否则可能出问题。

 

附:zInherit、xbObjects

分享到:
评论

相关推荐

    利用JavaScript实现图片标注——SearchMapIdentityTask

    `SearchMapIdentityTask`可能是一个自定义的JavaScript类,用于实现对地图上特定区域进行标注的功能。这个功能可以帮助用户在地图上查找、识别和标记特定的地理位置或对象,比如建筑物、道路、兴趣点等。 首先,...

    JavaScript代码生成器——Coffee Script.pdf

    JavaScript代码生成器——Coffee Script CoffeeScript是一种基于Ruby语言的编程语言,旨在通过简洁的编码方式生成JavaScript代码。它结合了Ruby的简洁和JavaScript的灵活性,使开发者可以通过简洁易读的语法撰写...

    教你一天玩转JavaScript(二)——完成对注册页面的数据的简单校验

    在“教你一天玩转JavaScript(二)——完成对注册页面的数据的简单校验”这个主题中,我们将深入探讨如何利用JavaScript进行有效的数据验证。 首先,我们需要了解JavaScript的基本语法和特性。JavaScript是一种解释型...

    JavaScript凌厉开发——Ext详解与实践 源码 源代码 part3

    JavaScript凌厉开发——Ext详解与实践 源码 源代码 part3 因为源代码比较大,压缩后76M左右 所以分为四个包上传

    JavaScript继承机制研究.pdf

    JavaScript是一门基于原型的语言,它不像其他面向对象的语言那样具有类的概念,而是通过原型链来实现继承。原型链是JavaScript继承机制的核心,它允许一个对象从另一个对象中继承属性和方法。通过原型链,JavaScript...

    JavaScript网页开发——体验式学习教程.pdf

    此外,教程还会涉及JavaScript的面向对象编程,包括构造函数、原型链、继承和封装。这些概念对于构建大型、复杂的Web应用至关重要。 ES6(ECMAScript 2015)是JavaScript的一个重要版本,引入了许多新特性,如箭头...

    JavaScript 继承详解(六)

    在本章中,我们将分析Prototypejs中关于JavaScript继承的实现。 Prototypejs是最早的JavaScript类库,可以说是JavaScript类库的鼻祖。 我在几年前接触的第一个JavaScript类库就是这位,因此Prototypejs有着广泛的...

    JavaScript程序设计——DOM访问实验报告.docx

    实验报告的主题是“JavaScript程序设计——DOM访问”,其目的是深入理解和掌握DOM(Document Object Model)在JavaScript中的应用,包括文档对象的属性、方法以及使用方式。DOM是HTML和XML文档的标准化表示,允许...

    javascript中如何实现封装,继承和多态

    javascript中如何实现封装,继承和多态

    Applet与Javascript的对话——让你的Javascript代码和Java Applet融洽地合作.pdf

    标题中的“Applet与Javascript的对话——让你的Javascript代码和Java Applet融洽地合作”指的是一种技术实现,即如何让JavaScript与Java Applet在Web应用中进行交互。这两种技术在早期Web开发中常常结合使用,以利用...

    JavaScript程序设计——页面设置与表单验证实验报告.docx

    实验报告的标题“JavaScript程序设计——页面设置与表单验证实验报告.docx”涉及的核心是JavaScript编程中的两个关键领域:页面设置和表单验证。在Web开发中,JavaScript是一种常用的客户端脚本语言,用于增强用户的...

    JavaScript例子——计算

    在这个"JavaScript例子——计算"中,我们可以推测这是一篇关于使用JavaScript进行数学计算的教程或者示例代码。博主"Fuhao9611"在iteye博客上分享了这个主题,可能包含了基础的算术运算、自定义函数、循环结构或者...

    JavaScript动态网页开发详解——源文件

    在"JavaScript动态网页开发详解——源文件"中,我们可以深入学习到JavaScript在网页开发中的应用技巧。此资料可能包含了JQUERY的官方实例全集,jQuery是一个高效、简洁且富有创造性的JavaScript库,它极大地简化了...

    浅析JavaScript实现基于原型对象的“继承”.pdf

    JavaScript还可以通过原型对象来实现继承。 原型对象 在JavaScript中,每个函数对象都有一个prototype属性,该属性指向函数的原型对象。原型对象是一个对象,它包含了构造函数的所有实例对象所共享的属性和方法。...

    JavaScript毕业设计——篮球赛事助手源码.zip

    JavaScript毕业设计——篮球赛事助手源码。已获高分通过项目。 在功能上实现创建比赛,统计参赛人员,统计比赛得分与犯规次数。 安装教程 启动服务器操作 (1) 找到服务器 woao_server 所在文件,点击进去文件 (2...

    zinherit 库

    zinherit库(&lt;script type="text/javascript" src="zinherit.js"&gt;)

    Android使用Html实现登录功能——重点掌握Webview js的使用

    为了实现JavaScript与Android的交互,我们需要使用`WebViewClient`和`WebChromeClient`。在Activity中,我们这样设置: ```java webView.setWebViewClient(new WebViewClient() { @Override public boolean ...

    网页设计与开发——HTML、CSS、JavaScript实例教程

    网页设计与开发——HTML、CSS、JavaScript实例教程网页设计与开发——HTML、CSS、JavaScript实例教程网页设计与开发——HTML、CSS、JavaScript实例教程网页设计与开发——HTML、CSS、JavaScript实例教程网页设计与...

Global site tag (gtag.js) - Google Analytics